Тестирование автоматического удаления дочерних 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.
Источник: Stack Overflow на русском