← Назад к вопросам
Какие плюсы и минусы использования shared pointer с QWidget?
2.2 Middle🔥 131 комментариев
#Qt и GUI
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Какие плюсы и минусы использования shared pointer с QWidget?
Проблема: shared_ptr с QWidget
QWidget — базовый класс для всех графических элементов в Qt. Он имеет свою систему управления памятью, несовместимую с std::shared_ptr.
Как работает Qt Parent-Child система
// Qt использует parent-child иерархию
QWidget* parent = new QWidget();
QWidget* child = new QWidget(parent);
// При удалении parent:
delete parent; // Автоматически удаляет child!
Qt сам управляет памятью через parent-child отношения.
Минусы использования shared_ptr с QWidget
1. Конфликт управления памятью
// ПЛОХО: два механизма управления памятью
std::shared_ptr<QWidget> widget(new QWidget());
// shared_ptr будет удалять через delete
// Qt parent-child система не сработает правильно
2. Double deletion (двойное удаление)
std::shared_ptr<QWidget> widget(new QWidget());
QWidget* parent = new QWidget();
widget->setParent(parent); // Qt устанавливает parent
// Когда widget выходит из scope:
// shared_ptr пытается delete → parent тоже delete → CRASH!
delete parent; // Double delete!
3. Утечки памяти при циклических ссылках
std::shared_ptr<QWidget> widget1(new QWidget());
std::shared_ptr<QWidget> widget2(new QWidget());
// Циклическая ссылка
widget1->setParent(widget2.get()); // Счётчик ссылок = 2
widget2->setParent(widget1.get()); // Счётчик ссылок = 2
// Когда переменные выходят из scope:
// Счётчики уменьшаются до 1, но не до 0 → утечка!
4. Ненужный overhead
// shared_ptr имеет 16 байт на 64-bit системе
// Qt уже управляет памятью через parent-child
std::shared_ptr<QWidget> widgets[1000000];
// Лишние 16MB памяти впустую!
Плюсы (редкие случаи)
1. Если нужен он без parent
// QWidget без parent = окно верхнего уровня
std::shared_ptr<QMainWindow> window(new QMainWindow());
// window может быть создана и уничтожена независимо
// Правильно, если окно не имеет явного parent
2. Упрощение кода (если аккуратно)
// Вместо:
QWidget* widget = new QWidget();
try {
do_something(widget);
} catch (...) {
delete widget; // Нужно не забыть
throw;
}
// С shared_ptr:
auto widget = std::make_shared<QWidget>();
// Автоматическое удаление в любом случае
Но это плохая идея, потому что Qt имеет свой механизм!
Правильный подход: НЕ использовать shared_ptr
1. Stack-based (рекомендуется)
// Лучший способ для локальных виджетов
void create_widgets() {
QWidget widget; // На стеке
QLabel label(&widget); // На стеке с parent
// Автоматическое удаление при выходе
}
2. Parent-child иерархия
class MainWindow : public QMainWindow {
public:
MainWindow() {
// Создаём child с parent = this
auto button = new QPushButton("Click me", this);
auto label = new QLabel("Hello", this);
// this автоматически удалит button и label
}
};
// При удалении MainWindow удалятся все children
3. Если нужна динамическая память
// Правильно: используй new с parent
void create_dialog() {
auto dialog = new QDialog(nullptr); // Окно верхнего уровня
dialog->show();
// dialog сама удалит себя при закрытии
// (Qt имеет WA_DeleteOnClose атрибут по умолчанию)
}
Когда МОЖНО использовать shared_ptr
Только если:
- Виджет создан БЕЗ parent
- Вы полностью берёте управление памятью на себя
- Вы НЕ используете parent-child иерархию для этого виджета
// Редкий случай: окно верхнего уровня с shared_ptr
std::shared_ptr<QMainWindow> app_window(new QMainWindow());
// Это работает, потому что:
// - Окно не имеет parent
// - Окно сама не удалит себя до выхода из shared_ptr
// - Нет конфликта с Qt управлением памятью
Альтернатива: unique_ptr
// Немного лучше, чем shared_ptr
std::unique_ptr<QWidget> widget(new QWidget());
// Но всё равно конфликтует с parent-child системой
widget->setParent(parent); // ОПАСНО!
Выводы
- НЕ используй shared_ptr с QWidget если используешь parent-child иерархию
- Используй stack-based или new с parent — это естественно для Qt
- QWidget сам управляет памятью через parent-child отношения
- shared_ptr добавляет confusion и overhead
- Если нужна smart pointer семантика — используй parent-child явно
- Только окна верхнего уровня могут быть в shared_ptr (и то редко)
Правило: Следуй конвенциям Qt, не боритесь с его архитектурой!