Тестирование автоматического удаления дочерних QObject
Эксперимент с 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".
Выводы из тестов:
- Если при создании
QObject-ов указывать родителемMainWindowто их деструкторы будут гарантированно вызваны после деструктораMainWindow. Если не указать родителя, то есть вероятность, что объекты останутся "пасынками" и их деструкторы вызваны не будут. - После добавления
QLabelна ToolBar или StatusBar они становятся родителямиQLabel(даже если изначально указатьMainWindow) и при их удалении автоматически освобождаютQLabel. - Если добавить
QLabelсначала на ToolBar, а затем на StatusBar то:QLabelбудет считать своим родителем StatusBar, однако удаление ToolBar тоже удалит этотQLabel;QLabelне будет отображаться ни на ToolBar, ни на StatusBar. Возможно это такой намёк на недопустимость такой ситуации, возможно просто глюк QT. Никаких сообщений об ошибке при этом не выводится.- Непонятно есть ли в такой ситуации неопределённое поведение из-за двойного удаления
QLabel- у меня программа ни разу не зависла и не упала из-за этого, но это ничего не значит. Попытка пошагать F11 ситуацию не прояснила - там слишком много всего происходит. Хотя понятно что в любом случае так делать не стоит.
QActionявляются специальным объектом и их поведение существенно отличается отQLabel:QActionкорректно отображаются и работают, имея нескольких родителей, например, меню и ToolBar;- автоматически удаляются только вместе с
MainWindowи только еслиMainWindowбыл указан как один из родителей. Удаление меню и ToolBar не удаляетQAction, даже если удалены все их родители.
Дополнительные моменты:
menuBar()иstatusBar()создаются по умолчанию (описаны вqmainwindow.h), их можно сразу использовать. ToolBar требуется создавать.- Попытка повторно вызвать
deleteLater()= неопределённое поведение и должна быть предотвращена в программе.deleteвместоdeleteLater()тоже может вызвать зависание или падение при двойном удалении меню, ToolBar и StatusBar.
Полный код проекта на GitHab.