Search code examples
c++qtdestruction

How does Qt delete objects ? And what is the best way to store QObjects?


I heard that objects in Qt will automatically delete their children, I want to know what will happen in those situations.

#include <QApplication>
#include <QLabel>
#include <QHBoxLayout>
#include <QWidget>

int main(int argc, char **argv)
{
    QApplication app(argc, argv);
/*
    QLabel label("label");      //  Program will crash. Destruct order is 1. widget, 2. layout, 3. label
    QHBoxLayout layout;         //  But layout will be deleted twice
    QWidget widget;
*/
    QWidget widget;             //  Program doesn't seem to crash but is it safe ? Does Qt use
    QHBoxLayout layout;         //  delete to operate on already destructed children ?
    QLabel label("label");

    layout.addWidget(&label);   //  layout is label's parent
    widget.setLayout(&layout);  //  widget is layout's parent
    widget.show();
    return app.exec();
}

Is this allowed in Qt? What does Qt do when destroying a child ?

BTW, I considered using smart pointers such as shared_ptr. But I think Qt would also delete the object which had already been destroyed by smart pointer too.

I know you would like to use new to allocate dynamic memory for objects. But I don't feel its reassuring, please tell me if there are any situations (e.g. exceptions) that will lead to memory leaks when relying on Qt's object tree to handle dynamic memory?

If I use objects rather than pointers to dynamically allocate objects, I have to consider the order of destruction of objects as long as they have ownership, which is tedious. I don't know whether it is good practice to use dynamic memory in Qt.

Do you have any suggestions or better solutions?


Solution

  • The QObject implementation of the Composite Design Pattern has been tried and tested through the many versions of Qt.

    The pattern requires that the composite object takes ownership of the children so, as long as the parenting has been done, you can be assured that the child QObjects will be destroyed when the parent is destroyed.

    Standard practice is to create child objects in heap memory and parent them immediately. If you don't parent immediately, you can explicitly parent using the setParent() function, or else parenting will be done automatically when you add the widget to a parent widget, either using addWidget() or addLayout().

    QLayout objects are size and layout managers of other QLayouts and of QWidgets. They don't own the objects they manage. The parent is actually the QWidget that the QLayout is the child of.

    You have a choice to create the root parent in stack memory or in heap memory.

    If you feel more comfortable with smart pointers, there are two classes that are specifically for QObjects: QPointer and QSharedPointer. Each has their pros and cons.

    #include <QApplication>
    #include <QLabel>
    #include <QHBoxLayout>
    #include <QWidget>
    
    int main(int argc, char **argv)
    {
        QApplication app(argc, argv);
    
        QWidget widget;             // Root parent so can create as a auto-deleting object on the stack
        QHBoxLayout *layout = new QHBoxLayout(&widget);         // Create on the heap and parent immediately
        QLabel *label = new QLabel("label", &widget);           // Create on the heap and parent immediately
    
        layout->addWidget(label);   // widget remains label's parent
        widget.setLayout(layout);   // widget is changed to layout's parent if necessary, as well 
                                    // as any widgets that layout manages
        widget.show();
        return app.exec();
    
        // layout and label are destroyed when widget is destroyed
    }