Qt: Можно ли создать дочерние объекты в родительском объекте?
В Qt я могу встроить дочерние виджеты в своих родительских элементах по композиции, или мне нужно создать их с помощью new
?
class MyWindow : public QMainWindow
{
...
private:
QPushButton myButton;
}
MyWindow::MyWindow ()
: mybutton("Do Something", this)
{
...
}
В документации указано, что любой объект, полученный из QObject
, будет автоматически уничтожен при уничтожении его родителя; это подразумевает вызов delete
, который в приведенном выше примере сработает.
Нужно ли использовать следующее?
QPushButton* myButton;
myButton = new QPushButton("Do Something", this);
ИЗМЕНИТЬ
Ответы весьма разнообразны и в основном сводятся к трем возможностям:
- Да, композиция в порядке. Qt может определить, как был выделен объект, и только
delete
объекты, выделенные кучей (как это работает?)
- Да, композиция в порядке, но не указывать родителя, поскольку родитель в противном случае вызывал бы
delete
на объект (но не будет виджет без родителя превратиться в верхнюю -level window?)
- Нет, виджеты всегда должны быть выделены в виде кучи.
Какой из них правильный?
Ответы
Ответ 1
Нестатические переменные-члены-кучи удаляются, когда начинается эта последовательность удаления конкретного объекта. Только когда все члены будут удалены, он перейдет к деструктору базового класса. Следовательно, член myButton QPushButton будет удален до вызова ~ QMainWindow(). И из документации QObject: "Если мы удалим дочерний объект перед его родителем, Qt автоматически удалит этот объект из родительского списка дочерних элементов". Следовательно, никакой аварии не произойдет.
Ответ 2
В документации говорится, что любой объект, полученный из QObject, будет автоматически уничтожен при уничтожении его родителя; это означает, что нужно удалить
Нет. Он подразумевает вызов деструктора этого конкретного объекта.
Скажем в вашем примере, если MyWindow
уничтожен, это означает, что деструктор MyWindow
был вызван. Это, в свою очередь, вызовет деструктор myButton
, который уже реализован в QPushButton
.
Если у вас есть составная сущность, только деструктор будет вызываться на этом объекте, но не delete
, и поэтому он не будет сбой.
Родительские отношения с дочерними элементами в Qt не требуют, чтобы они были в стеке или куче. Это может быть во всем.
Аналогичный пример в родительских дочерних отношениях над стеком находится над здесь.
НТН..
Ответ 3
Деревья объектов и собственность отвечает на ваш вопрос. В основном, когда дочерний объект создается в куче, он будет удален его родителем.
С другой стороны, когда дочерний объект создается в стеке, порядок уничтожения важен. Ребенок будет уничтожен до его родителем и удалит себя из своего родительского списка, чтобы его деструктор не вызывался дважды.
В этой ссылке также есть пример, показывающий проблемный порядок уничтожения.
Ответ 4
Объект будет уничтожен только тогда, когда он имеет родительский указатель, поэтому вы можете использовать:
MyWindow::MyWindow ()
: mybutton("Do Something", 0)
{
...
}
Ответ 5
Вы должны создать его в куче, так как QObject уничтожит его:
class MyWindow : public QMainWindow
{
...
private:
QPushButton *myButton;
}
MyWindow::MyWindow ()
: mybutton( new QPushButton( "Do Something", this) )
{
...
}
Ответ 6
вызов оператора delete
не приведет к сбою приложения ur, вы можете прочитать следующую цитату
Механизм родитель-ребенок Qt реализован в QObject. Когда мы создаем объект (виджет, валидатор или любой другой вид) с родителем, родитель добавляет объект в список своих дочерних элементов. Когда родитель удален, он просматривает список своих детей и удаляет каждого дочернего элемента. Затем сами дети удаляют всех своих детей и т.д. Рекурсивно, пока не останется. Механизм parent-child значительно упрощает управление памятью, что снижает риск утечки памяти. Единственными объектами, которые мы должны назвать delete, являются объекты, которые мы создаем с новыми, и которые не имеют родителя. И если мы удалим дочерний объект перед его родителем, Qt автоматически удалит этот объект из родительского списка дочерних элементов.
обратите внимание, что родительский аргумент NULL
по умолчанию (аргумент по умолчанию)
это конструктор QPushButton
QPushButton ( const QString & text, QWidget * parent = 0 )
поэтому вы можете использовать
MyWindow::MyWindow () : mybutton( new QPushButton( "Do Something") ){ ... }
и u может вызывать delete
на любом компоненте и в любое время
Qt позаботится об этой точке
Ответ 7
Позвольте мне просто указать источник здесь.
816 QObject::~QObject()
817 {
818 Q_D(QObject);
819 d->wasDeleted = true;
820 d->blockSig = 0; // unblock signals so we always emit destroyed()
821
...
924
925 if (!d->children.isEmpty())
926 d->deleteChildren();
927
928 qt_removeObject(this);
929
930 if (d->parent) // remove it from parent object
931 d->setParent_helper(0);
932
933 #ifdef QT_JAMBI_BUILD
934 if (d->inEventHandler) {
935 qWarning("QObject: Do not delete object, '%s', during its event handler!",
936 objectName().isNull() ? "unnamed" : qPrintable(objectName()));
937 }
938 #endif
939 }
...
1897 void QObjectPrivate::deleteChildren()
1898 {
1899 const bool reallyWasDeleted = wasDeleted;
1900 wasDeleted = true;
1901 // delete children objects
1902 // don't use qDeleteAll as the destructor of the child might
1903 // delete siblings
1904 for (int i = 0; i < children.count(); ++i) {
1905 currentChildBeingDeleted = children.at(i);
1906 children[i] = 0;
1907 delete currentChildBeingDeleted;
1908 }
1909 children.clear();
1910 currentChildBeingDeleted = 0;
1911 wasDeleted = reallyWasDeleted;
1912 }
Итак, как вы можете видеть, QObject
действительно delete
каждый из своих дочерних элементов в деструкторе. Кроме того, деструктор выполняется перед деструкторами любых членов; поэтому, если рассматриваемый композит равен родительскому - тогда член QObject
не будет иметь возможности удалить себя из списка дочерних элементов его родителя.
Это, к сожалению, означает, что вы не можете составить QObject
в свой родитель. Но вы можете сочинять в другие объекты, а также выделять в стеке - как только вы гарантируете уничтожить объект или reset его родительский элемент до 0 до того, как родитель начнет разрушать.