Тестирование автоматического удаления дочерних QObject

Рейтинг: 1Ответов: 0Опубликовано: 28.07.2025

Эксперимент с QT 6.9.1. под windows 10. Это не вопрос, а исследование.

Нашёл в интернете что при освобождении QObject-ов QT автоматически освобождает и их потомков. Т.е. при работе с QWidget-ами можно не заморачиваться ни с delete ни с умными указателями.

Но эти упоминания оказались отрывочными и невнятными, поэтому решил поэкспериментировать. В качестве подопытных выбрал QAction и QLabel, как распростанённые и типовые. Написал для них наследников, добавляющих вывод отладочной информации в деструкторе.

class Action : public QAction
{
public:
    explicit Action(const QString &text, QObject *parent = nullptr)
        : QAction(text, parent){};

    ~Action(){
        qDebug() << "delete QAction " << text();
    };
};

А в MainWindow конструктор и деструктор добавил отладочный вывод "Start" и "Finish".

Выводы из тестов:

  1. Если при создании QObject-ов указывать родителем MainWindow то их деструкторы будут гарантированно вызваны после деструктора MainWindow. Если не указать родителя, то есть вероятность, что объекты останутся "пасынками" и их деструкторы вызваны не будут.
  2. После добавления QLabel на ToolBar или StatusBar они становятся родителями QLabel (даже если изначально указать MainWindow) и при их удалении автоматически освобождают QLabel.
  3. Если добавить QLabel сначала на ToolBar, а затем на StatusBar то:
    • QLabel будет считать своим родителем StatusBar, однако удаление ToolBar тоже удалит этот QLabel;
    • QLabel не будет отображаться ни на ToolBar, ни на StatusBar. Возможно это такой намёк на недопустимость такой ситуации, возможно просто глюк QT. Никаких сообщений об ошибке при этом не выводится.
    • Непонятно есть ли в такой ситуации неопределённое поведение из-за двойного удаления QLabel - у меня программа ни разу не зависла и не упала из-за этого, но это ничего не значит. Попытка пошагать F11 ситуацию не прояснила - там слишком много всего происходит. Хотя понятно что в любом случае так делать не стоит.
  4. QAction являются специальным объектом и их поведение существенно отличается от QLabel:
    • QAction корректно отображаются и работают, имея нескольких родителей, например, меню и ToolBar;
    • автоматически удаляются только вместе с MainWindow и только если MainWindow был указан как один из родителей. Удаление меню и ToolBar не удаляет QAction, даже если удалены все их родители.

Дополнительные моменты:

  1. menuBar() и statusBar() создаются по умолчанию (описаны в qmainwindow.h), их можно сразу использовать. ToolBar требуется создавать.
  2. Попытка повторно вызвать deleteLater() = неопределённое поведение и должна быть предотвращена в программе.
    • delete вместо deleteLater() тоже может вызвать зависание или падение при двойном удалении меню, ToolBar и StatusBar.

Полный код проекта на GitHab.

Ответы

Ответов пока нет.