How Does Qt Delete Objects? and How to Store Qobjects

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

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
}

how can Qt delete QObjects?

Let the source code speak instead of mere answers. Here is what QObject's internals do:

for (int i = 0; i < children.count(); ++i) {
currentChildBeingDeleted = children.at(i);
children[i] = 0;
delete currentChildBeingDeleted;
}
children.clear();

Function with the code above is called in destructor. So, it is pretty simple. Parent stores pointers to all of its children. When parent's destructor is being called, it deletes all it's children. This is recursive, as calling delete on object calls its destructor

Why Qt can safely delete without concerns about runtime library

Actually, due to name mangling, exporting C++ interface nearly forces You to use the same version of compiler and runtime library. This in very crude way allows Qt to assume that delete is safe to call.

Destruction of QObjects

So why does Documentation says that order of destruction doesn't matter?

It means that you don't NEED to delete objects manually. Qt will register object within parent/child hierarchy and kill it when necessary.

Of course, it can't track all pointers you might have stored somewhere. So if you take a pointer to object, then delete object's parent, then attempt to delete pointer you took, that'll be entirely your fault.

Should we be always careful about deleting child object?

No. When you delete child object it will unregister itself from its parent.
If you delete second, then delete first, program will work fine.
So you should remember that once you killed an object all its children are gone.

By the way, Qt has QPointer class made specifically for this situation, so you should use it instead of raw pointers. QPointer will set itself to zero when object it points to is destroyed.

But if I delete it causes segmentation fault.

It means that your program has a bug you haven't fixed. And most likely (98% possibility) the bug is within your code, and is not Qt's fault. Debug the segfault and see where it happens.


explanation

QWidget* first = new QWidget;
QWidget* second = new QWidget(first);
delete first;
delete second;

When you delete first it also deletes second, because second is its child.
However, your pointer second will not be automatically updated. It'll turn into dangling pointer (points at object that is no longer there), and attempt to delete it, will trigger undefined behavior, which, in your case, will crash the program.

If you INSIST on keeping separate pointer for second AND deleting second after first (again), you can use something like this (don't forget to #include <QPointer>):

QPointer<QWidget> first = new QWidget,
second = new QWidget(first);
delete first;
delete second;

However, there's no real need for that, and normally people simply do this:

QWidget *first = new QWidget,
*second = new QWidget(first);
delete first;//second is deleted automatically

Normally, in C++ you have to delete every object you allocated (with new) yourself, manually. This is error-prone, requires you to write a destructor, and you might somemetimes forget about it, which will result in memory leak.
However, QObject automatically deletes all its children within its destructor, which means it is perfectly okay to do this:

 QObject *a = new QObject();
QObject *b = new QObject(a);
b = new QObject(a);
b = new QObject(a);

As long as you remember to delete top-level object, all its child resources will be automatically freed.

However, Qt cannot track pointers you stored. So if you do something like this:

QObject *a = new QObject(), *b = a;
delete a;

It will not update existing raw pointers. That's standard C++ behavior, by the way.

That's what QPointers are for:

QObject *a = new QObject(), *b = a;
QPointer<QObject> c = a;
delete a;
//at this point c is set to zero. a and b still point at previous object locations.

c++ Delete derived from base class like QObject do

I'm going to prefix this by saying I didn't actually test this, but the code should be workable.

I don't think you really need the extra Storage class, this can simply be done directly in the Base class instead. Further, in the Derived class's constructor, you are passing a pointer to a pointer to the parent. You only want to pass the pointer itself, otherwise you will be getting some errors, as you will be referencing objects which do not exist.

Also, I believe your call in the Base class's constructor to the Storage::deleteBase() function will delete too much, and invalidate objects prematurely. This would then lead to undefined behaviour.

class Base {
public:
Base( Base *parent = nullptr ) {
if ( parent )
parent->addChild( this );
}
virtual ~Base() {
for ( Base *child : children )
delete child;
}
private:
void addChild( Base *child ) {
children.push_back( child );
}
std::vector<Base*> children;
};

class Derived : public Base {
public:
Derived( Base *parent = nullptr ) : Base( parent ) {}
}

Shall I delete QObject pointers after using them?

No, You shouldn't delete these objects, they are managed by their parent QObjects, see QObject trees and ownership:

When using findChild, you are getting a pointer to the same object managed by this parent.

So, loginField, passwordField are deleted when their parent widget is deleted (this instance in your case). If you delete them, they will disappear from the GUI. You have to keep them until the parent widget decides they are no longer needed (that is the time when it is destructed):

You can also delete child objects yourself, and they will remove themselves from their parents. For example, when the user removes a toolbar it may lead to the application deleting one of its QToolBar objects, in which case the tool bar's QMainWindow parent would detect the change and reconfigure its screen space accordingly.

What is the delete sequence of QObject with default parent in Qt?

If we're talking about pointers to QObject, no, they won't be deleted. You will have a memory leak unless you delete them manually so there won't be any sequence of deleting.

Pointers don't release their memory unless delete is called on them. Say you have a pointer to a memory location to which no other pointer points. If that pointer goes out of scope and you don't call delete on it, you will have a memory leak because if no other pointer points to that memory location then you won't have access to that memory location anymore. And you get an inaccessible and useless chunk of memory.

In classes, destructors have the purpose of releasing the memory when deleted. Destructors are called when instances of the classes go out of scope(in case of instances allocated on the stack i.e. static, e.g. MyClass x;) or when delete is called of them(in case of pointers i.e. dynamic, e.g. MyClass *x = new MyClass;)

Qt created a clever mechanism so that programmers won't have to think that much of these things because lots of errors occur because of them. So Qt introduced parents, i.e. if you set a QObject a parent, when you will delete the parent the QObject will be deleted as well.

If you use QObject pointers as members in a class and don't set them a parent, when an instance of that class gets deleted you will have a memory leak unless, of course, you delete them manually in the destructor.

For example the following implementation will create memory leak if used:

class MyObject : public QObject
{
public:
MyObject(QObject *parent = 0);
~MyObject();

private:
QTimer *m_pTimer;
}

MyObject::MyObject(QObject *parent) : QObject(parent)
{
m_pTimer = new QTimer; // memory leak when this will be destroyed
}

MyObject::~MyObject()
{
}

In order to fix this you should provide this as parent:

MyObject::MyObject(QObject *parent) : QObject(parent)
{
m_pTimer = new QTimer(this);
}

or

MyObject::~MyObject()
{
delete m_pTimer;
}

In an implementation like this:

class MyObject : public QObject
{
public:
MyObject(QObject *parent = 0);
~MyObject();

private:
QTimer m_timer;
}

MyObject::MyObject(QObject *parent) : QObject(parent)
{
// Do stuff
}

MyObject::~MyObject()
{
}

where you don't have pointers and memory allocated on the heap, all the members are destroyed when getting out of scope i.e. when the instance of the class(in our case MyObject) gets out of scope.

I consider worth mentioning here the layouts system in Qt.

Lets say you have a QWidget with a QPushButton inside it. If you create a QLayout, add the QPushButton to the QLayout and set the QLayout on the QWidget with QWidget::setLayout, automatically a child-parent relationship will be created between the QPushButton and the QWidget and also between the QLayout and the QWidget.

Here's an example:

class Widget : public QWidget
{
Q_OBJECT

public:
explicit Widget(QWidget *parent = 0);
~Widget();

private:
QGridLayout *m_pLayout;
QPushButton *m_pButton;
};

Widget::Widget(QWidget *parent) :
QWidget(parent)
{
m_pLayout = new QGridLayout;
m_pButton = new QPushButton;
m_pButton->setText("Push me!");

m_pLayout->addWidget(m_pButton, 0, 0);

setLayout(m_pLayout); // In this moment *this* will be automatically
// set as parent for both m_pLayout and m_pButton
// even though no parent was passed to their constructors.
}

Widget::~Widget()
{
}

I hope this helps.

Should destructor be called on member objects

For the first question yes. You can check the Qt docs here
where it is stated clearly:

QObjects organize themselves in object trees. When you create a
QObject with another object as parent, the object will automatically
add itself to the parent's children() list. The parent takes ownership
of the object; i.e., it will automatically delete its children in its
destructor. You can look for an object by name and optionally type
using findChild() or findChildren().

For the second question, the answer deserves a little bit more of explanation. If you have QObject pointers members that are not children of your object, you have to handle their disposal manually in the destructor of your class.

You can in theory use delete on any QObject* to invoke its destructor, but since Qt objects have a powerfull event system based on signals/slots, you must be aware of the interactions with event loops. If you brutally delete a QObject connected to another QObject while the latter one is still processing a signal coming from the first one, you may end up with some problems.

This holds in both mono and multi-threaded applications. You should therefore avoid the use of delete in favor of QObject::deleteLater() that will defer the deletion of the QObject until all the signal/slots related to it have been processed.

Lastly, in the context of the implementation of a destructor it doesn't really matter if you set the pointer to null, because it will be unavailable for further use anyway. It may be important if you delete the pointee in some other method, while your instance is still alive, and you set the pointer to null to flag it as uninitialized.

Optimal way to self-delete QObjects

If the parentYouHaveToDeleteChild signal is connected to the deleteChild slot, there is effectively no difference between the two methods you've presented. The program will not return to the event loop before calling the slot.

Except that the second method adds the overhead of a signal/slot call.

Does QObject distinguish between stack and heap allocated children when deleting?

However, it is not necessary for children to be dynamically allocated,
and it is perfectly legal to build QObject trees with stack allocated
objects.

No. See QObject::~QObject():

Warning: All child objects are deleted. If any of these objects are on
the stack or global, sooner or later your program will crash.



Related Topics



Leave a reply



Submit