In Qt, can I embed child widgets in their parent via composition, or do I have to create them with new
?
class MyWindow : public QMainWindow
{
...
private:
QPushButton myButton;
}
MyWindow::MyWindow ()
: mybutton("Do Something", this)
{
...
}
The documentation says that any object derived from QObject
will automatically destroyed when its parent is destroyed; this implies a call to delete
, whcih in the above example would crash.
Do I have to use the following?
QPushButton* myButton;
myButton = new QPushButton("Do Something", this);
EDIT
The answers are quite diverse, and basically boil down to three possibilities:
- Yes, composition is ok. Qt can figure out how the object was allocated and only
delete
heap-allocated objects (How does this work?) - Yes, composition is ok, but don't specify a parent, since the parent would otherwise call
delete
on the object (But won't a parent-less widget t开发者_开发百科urn into a top-level window?) - No, widgets always have to be heap-allocated.
Which one is correct?
The non-static, non-heap member variables are deleted when that particular object's delete sequence starts. Only when all members are deleted, will it go to the destructor of the base class. Hence QPushButton myButton member will be deleted before ~QMainWindow() is called. And from QObject documentation: "If we delete a child object before its parent, Qt will automatically remove that object from the parent's list of children". Hence no crash will occur.
Object trees & ownership answers your question. Basically when the child object is created on the heap it will be deleted by its parent.
On the other hand when the child object is created on the stack the order of destruction is important. The child will be destroyed before its parent and will remove itself from its parent's list so that its destructor is not called twice.
There is also an example in that link that shows problematic order of destruction.
The documentation says that any object derived from QObject will automatically destroyed when its parent is destroyed; this implies a call to delete
No. It implies a call to the destructor of that particular entity.
Say in your example, if MyWindow
is destroyed, it means the destructor of the MyWindow
has been called. Which in turn will call the destructor myButton
which is implemented already in QPushButton
.
If you have composite entity, just the destructor will be called on that entity but not delete
and so it won't crash.
Parent child relationships in Qt doesn't require specifically to be in a stack or heap. It can be in anything.
A similar example in parent child relationship over a stack is over here.
HTH..
The object will be destroyed only when it has a parent pointer, so you can use:
MyWindow::MyWindow ()
: mybutton("Do Something", 0)
{
...
}
You should create it on heap, since QObject will destroy it :
class MyWindow : public QMainWindow
{
...
private:
QPushButton *myButton;
}
MyWindow::MyWindow ()
: mybutton( new QPushButton( "Do Something", this) )
{
...
}
calling delete
operator will not crash ur application, you can read the following quote
Qt's parent–child mechanism is implemented in QObject. When we create an object (a widget, validator, or any other kind) with a parent, the parent adds the object to the list of its children. When the parent is deleted, it walks through its list of children and deletes each child. The children themselves then delete all of their children, and so on recursively until none remain. The parent–child mechanism greatly simplifies memory management, reducing the risk of memory leaks. The only objects we must call delete on are the objects we create with new and that have no parent. And if we delete a child object before its parent, Qt will automatically remove that object from the parent's list of children.
note that the parent argument is NULL
by default (default argument)
this is QPushButton Constructor
QPushButton ( const QString & text, QWidget * parent = 0 )
so u can use
MyWindow::MyWindow () : mybutton( new QPushButton( "Do Something") ){ ... }
and u can call delete
on any component and any time
Qt will take care for this point
Let me just quote the source here.
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 }
So as you can see, QObject
does indeed delete
each of its children in the destructor. In addition, the destructor is executed before destructors of any members; so if the composite in question equals the parent – then member QObject
won't have any chance to remove itself from the children list of its parent.
This, unfortunately, means that you cannot compose a QObject
into its parent. But you can compose into other objects, as well as allocate on stack – as soon as you guarantee to destruct the object or reset its parent to 0 before the parent starts destructing.
精彩评论