← Назад к вопросам

Какие плюсы и минусы использования 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

Только если:

  1. Виджет создан БЕЗ parent
  2. Вы полностью берёте управление памятью на себя
  3. Вы НЕ используете 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, не боритесь с его архитектурой!

Какие плюсы и минусы использования shared pointer с QWidget? | PrepBro