ChatGPT解决这个技术问题 Extra ChatGPT

Memory management in Qt?

I'm quite new to Qt and am wondering on some basic stuff with memory management and the life of objects. When do I need to delete and/or destroy my objects? Is any of this handled automatically?

In the example below, which of the objects I create do I need to delete? What happens to the instance variable myOtherClass when myClass is destroyed? What happens if I don't delete (or destroy) my objects at all? Will that be a problem to memory?

MyClass.h

class MyClass
{

public:
    MyClass();
    ~MyClass();
    MyOtherClass *myOtherClass;
};

MyClass.cpp

MyClass::MyClass() {
    myOtherClass = new MyOtherClass();

    MyOtherClass myOtherClass2;

    QString myString = "Hello";
}

As you can see this is quite newbie-easy stuff but where can I learn about this in an easy way?


u
user2567875

If you build your own hierarchy with QObjects, that is, you initialise all newly created QObjects with a parent,

QObject* parent = new QObject();
QObject* child = new QObject(parent);

then it is enough to delete the parent, because the parents destructor will take care of destroying child. (It does this by issuing signals, so it is safe even when you delete child manually before the parent.)

You could also delete the child first, the order doesn't matter. For an example where the order does matter here's the documentation about object trees.

If your MyClass is not a child of QObject, you’ll have to use the plain C++ way of doing things.

Also, note that the parent–child hierarchy of QObjects is generally independent of the hierarchy of the C++ class hierarchy/inheritance tree. That means, that an assigned child does not need to be a direct subclass of it’s parent. Any (subclass of) QObject will suffice.

There might be some constraints imposed by the constructors for other reasons, however; such as in QWidget(QWidget* parent=0), where the parent must be another QWidget, due to e.g. visibility flags and because you’d do some basic layout that way; but for Qt's hierarchy system in general, you are allowed to have any QObject as a parent.


(It does this by issuing signals, so it is safe even when you delete child manually before the parent.) -> This is isn't the reason why it is safe. In Qt 4.7.4, QObject children get deleted directly (via delete, see qobject.cpp, line 1955). The reason why it is safe to delete child objects first is that a QObject tells its parent to forget it when it gets deleted.
I would add that you must ensure the destructors of descendents are virtual for this to be true. If ClassB inherits from QObject and ClassC inherits from ClassB, then ClassC will only get properly destroyed by Qt's parent-child relationship if ClassB's destructor is virtual.
The link in the answer is now broken (not surprising after nearly 4 years...), maybe it was something like this qt-project.org/doc/qt-4.8/objecttrees.html ?
@Phlucious QObject's destructor is already virtual, which makes every subclass's destructor virtual automagically.
If one class somewhere in the inheritance tree has a virtual destructor, every child class below will have a virtual destructor. Now, if there is a leaf parent class outside such a virtual destructor chain without a virtual destructor, I believe you can have issues if you delete a pointer to that specific class when the actual object is somewhere further down that chain. In the case of a child class of QObject and deleting a QObject pointer to an instance of that child class, there is never an issue, even if you forget the virtual keyword in that subclass's destructor declaration.
G
Georg Schölly

I'd like to extend Debilski's answer by pointing out that the concept of ownership is very important in Qt. When class A assumes ownership of class B, class B is deleted when class A is deleted. There are several situations where one object becomes the owner of another, not just when you create an object and specify its parent.

For instance:

QVBoxLayout* layout = new QVBoxLayout;
QPushButton someButton = new QPushButton; // No owner specified.
layout->addWidget(someButton); // someButton still has no owner.
QWidget* widget = new QWidget;
widget->setLayout(layout); // someButton is "re-parented".
                           // widget now owns someButton.

Another example:

QMainWindow* window = new QMainWindow;
QWidget* widget = new QWidget; //widget has no owner
window->setCentralWidget(widget); //widget is now owned by window.

So, check the documentation often, it generally specifies whether a method will affect the ownership of an object.

As stated by Debilski, these rules apply ONLY to objects that derive from QObject. If your class does not derive from QObject, you'll have to handle the destruction yourself.


Whats the difference between writing: QPushButton *someButton = new QPushButton(); or QPushButton someButton = new QPushButton or just QPushButton someButton;
Ehh, there's a huge difference between QPushButton *someButton = new QPushButton; and QPushButton someButton;. The former will allocate the object on the heap, whereas the latter will allocate it on the stack. There's no difference between QPushButton *someButton = new QPushButton(); and QPushButton someButton = new QPushButton;, both of them will call the default constructor of the object.
I'm very new to this so sorry for asking but what's the difference between "allocate the object on the heap" and "allocate it on the stack"? When should I use heap and when should I use stack? Thanks!
You need to read about dynamic allocations, object scope and RAII. In the case of plain C++, you should allocate objects on the stack whenever possible as the objects are automatically destructed when they run out of scope. For class members, it is better to allocate the objects on the heap due to performance. And whenever you want an object to "outlive" the execution of a function/method, you should allocate the object on the heap. Again, these are very important topics that require some reading.
@Austin The general statement that you should allocate class members on the heap for performance is bullocks. It really depends and you should prefer variables with automatic storage duration until you find a problem with purrformance.
M
MLandgraf

Parent(either QObject object or its derived class) has a list of pointer to its children(QObject/its derived). The parent will delete all the objects in its child list while the parent is destroyed. You can use this property of QObject to make child objects to delete automatically when ever the parent is deleted. The relation can be established using the following code

QObject* parent = new QObject();
QObject* child = new QObject(parent);
delete parent;//all the child objects will get deleted when parent is deleted, child object which are deleted before the parent object is removed from the parent's child list so those destructor will not get called once again.

There are other way to manage memory in Qt, using smartpointer. The following article describes various smart pointers in Qt. https://www.qt.io/blog/2009/08/25/count-with-me-how-many-smart-pointer-classes-does-qt-have


K
Khaled

To add on to these answers, for vérification, I would recommend you to utilize Visual Leak Detetor library for your Visual c++ projets, including Qt projects since its based on c++, this library is compatible with new, delete, free and malloc statements, it is well documented and easy to use. Don't forget that when you create your own QDialog or QWidget inherited interface class, and then create a new object of this class, don't forget to execute setAttribute(Qt::WA_DeleteOnClose) function of your object.