Memory Management in Qt

Qt Widget Memory Management

Widgets are destroyed by their parents (when you call layout->addWidget, for example, layout takes ownership of the passed widget), when those are destroyed. In your case, window will get destroyed at the end of the scope (when app.exec returns), which in turn will destroy the layout, which in turn will destroy label and the edit box.

Object Trees & Ownership in Qt docs.

Right usage of Qt5 elements regarding memory management

Here is a summary: (from https://forum.qt.io/topic/65443/raw-pointers-in-qt/5)

class MyObject : public QObject
{
Q_OBJECT

public:
MyObject(QObject *parent = nullptr) {
obj1 = new QObject(this); // Sets the parent using the 'parent' constructor parameter

obj2 = new QObject;
obj2->setParent(this); // Sets the parent using QObject::setParent()

obj3 = new QObject; // No parent
}

private:
QObject *obj1;
QObject *obj2;
QObject *obj3;
};

When you delete your MyObject, it will automatically delete obj1 and obj2 because of the parent-child relationship. However, obj3 will not get deleted because you did not set it as a child, so the memory for obj3 gets leaked.

There are many ways to handle deletions:

  • do it manually
  • use smart pointers
  • use QObject's parent-child system

So there is no problem to use smart pointers with Qt5 if you don't mix it with parent-child system!

QObject memory management and smart pointers

As you probably know, at destruction QObject will destroy all their children, this is what we call "QObject memory management". Children are typically added to a QObject *parent from their constructor with new QObject(parent);.

Smart pointers on the other hand, is more a category than a specific type,
including shared pointers, auto pointers, etc. which have an implementation in both the STL and Qt in C++ (only to name those two).

So even though they are not directly comparable, I would sum it that way:

Use QObject memory management when ...

  1. Your object is a QWidget, of course, or GUI related
  2. You don't need/want to store the pointer

    MyObject *object = new MyObject(this);
    object->setSomething();
    // And you don't ever need to access it later
  3. Your object only tied to its parent lifespan. In that case, you won't need to create an additional smart pointer over it, and you will be able to store it as a simple QObject*

  4. You need the QObject hierarchy and/or find features, which let you do stuff like below. See QObject documentation for more details.

    // Get children
    auto childrenList = this->children();
    // Find a specific child
    MyObject* child = this->findChild<MyObject*>("specific name");

If you fall in one of these cases and your object is shared, you might want to use QObjectPointer type too, which will be automatically reset whenever the pointed QObject is destroyed.

Use smart pointers when ...

  1. Your object is not a QObject based type, of course
  2. Your object is local (deleted at the end of the scope), in which case you need a QScopedPointer or std::unique_ptr. QObject parenting would be most likely overkill here, and dangerous.
  3. Your object is shared, and thus requires a QSharedPointer or std::shared_pointer/std::weak_ptr. Again, QObject parenting could delete your QObject at any time, which is not what you want when using shared pointers.

None of the above?

Then it is up to you, they serve different purposes.

  • In Qt GUI related code, I tend to prefer QObject parenting: simple, and will nicely integrate with Qt code. Careful as the call stack will be a little less clear to understand if you are debugging though.
  • Outside of the UI, or to interface with non-UI related code, I prefer pure C++: The less external dependencies, the better!

How C++/Qt - Memory allocation works?

A quick peek into qtreewidget.cpp shows this:

void QTreeWidget::clear()
{
Q_D(QTreeWidget);
selectionModel()->clear();
d->treeModel()->clear();
}

void QTreeModel::clear()
{
SkipSorting skipSorting(this);
for (int i = 0; i < rootItem->childCount(); ++i) {
QTreeWidgetItem *item = rootItem->children.at(i);
item->par = 0;
item->view = 0;
delete item; // <<----- Aha!
}
rootItem->children.clear();
sortPendingTimer.stop();
reset();
}

So it would appear that your call to widget->addTopLevelItems() does indeed cause the QTreeWidget to take ownership of the QTreeWidgetItems. So you shouldn't delete them yourself, or hold them in a shared_ptr, or you'll end up with a double-delete problem.

Which memory management method should we use in Qt?

As you know, Qt has a model for which:

QObjects organize themselves in object trees. When you create a QObject with another object as parent, it's added to the parent's children() list, and is deleted when the parent is.

Moreover:

You can also delete child objects yourself, and they will remove themselves from their parents.

Because of that, as long as you use that model, you won't have problems of double frees.

That said, a common approach I've seen and used (but be aware that there was ever a reason to do that) is to create two layers, the former as a purely Qt-based one and the latter completely Qt-unaware. Of course, it requires a thin layer that translate pieces of information back and forth.

In such a model, it is reasonable to see both the approaches applied, never mixed and correctly working.

So, which is the best one? It depends on your target.

I've used a mixed approach in cases where the underlying layer was meant as a standalone codebase on top of which I was able to create an interface using my preferred library, but also I wanted to be free to switch to whatever library for the UI.

If this is not the case and your project is a purely Qt-based one, there is no reason not to base everything on the model on which Qt itself is based.

Qt Memory Management for Qt objects

What you suggested is valid only for classes inheriting QObject (ie having QObject as one of their superclass). These properties don't apply to other classes (even built-inQt ). As QColor not a subclass of QObject, the object referenced by m_pColor will not be destroyed when Widget is destroyed. You will have to do it manually.

Smart pointers memory managers in Qt

as I fear some platform may not yet be supported

That feels like incorrect guess. Every mobile platforms support it these days and Qt does depend on the standard library explicitly these days.

Even if it did not, you do not need to implement your own smart pointer as Qt has been providing these for ages:

  • QPointer
  • QSharedPointer
  • QWeakPointer
  • QScopedPointer

Here you can find a thorough explanation about them by Thiago.

So, the bottom line is just this: do not implement them yourself because you are reinventing the wheel and it is likely that you will need to fix bugs that had been fixed awhile ago. The ready-made solution will probably also scale better than your implementation from scratch and maintained by others without you needing to spend time with it.

If you only wish to deal with the automated construction and decontruction of QObject subclasses, you could also use the Qt parent/child hierarchy. Here you can read more about that one:

Object Trees & Ownership

That means, you could write something like this for QWidgets (because they are also QObjets):

QMenu *mainMenu = new QMenu(this);
QToolBar *toolBar = new QToolBar(this);

where this is basically the parent, like mainwindow, or it could be the Qt application object if you have one top-level widget, for instance, and so on.

C++ QT Memory Allocation

If the object has a parent, you don't need to release it - it will be done automatically by the QT memory management system.

In your specific example, you do need to delete your object, since it has no parent. Even if you do not do it, it will be done by your OS when app.exec(); returns.


From the documentation about the qt's object trees :

QObjects organize themselves in object trees. When you create a QObject with another object as parent, it's added to the parent's children() list, and is deleted when the parent is.



Related Topics



Leave a reply



Submit