PDA

View Full Version : Dynamical objects (by operator new) in Qt



spherrra
10th October 2011, 16:21
How to delete dynamic objects (creating by operator new)? Freed memory by the operating system or some Qt-means? Thanks.

wysota
10th October 2011, 16:27
Use the "delete" operator.

spherrra
10th October 2011, 16:33
Use the "delete" operator.
Yes, I know;) But in Examples and Demos uses no one nowhere operator delete in destructors. I asked another question ;)

d_stranz
10th October 2011, 16:36
In general, any object instance that is created by operator new() and is given to another object instance as its child does not have to be deleted. Qt QObject parent-child relationships will ensure that when an instance's parent gets deleted, all of its children will be deleted, too.

Since most apps create QApplication and QMainWindow instances on the stack, in main(), when the program exits these instances and all of their heap-created children will be automatically cleaned up.

One exception to this is the use of heap-allocated QAction instances. One instance of a QAction can be shared with multiple object instances (such as assigning the same QAction instance to a menu, push-button, and toolbar button). These should be made member variables of some higher-level GUI class (such as your QMainWindow) and should be deleted in the destructor of that class. Assigning a QAction to a menu item does not establish a parent-child relationship.

wysota
10th October 2011, 16:44
I asked another question ;)

I don't see any other questions:

How to delete dynamic objects (creating by operator new)? Freed memory by the operating system or some Qt-means? Thanks.

You asked how to delete objects created using "new" operator. That's what you use the "delete" operator for.

It really pays off to invest some time in learning to write proper English sentences.



One exception to this is the use of heap-allocated QAction instances. One instance of a QAction can be shared with multiple object instances (such as assigning the same QAction instance to a menu, push-button, and toolbar button). These should be made member variables of some higher-level GUI class (such as your QMainWindow) and should be deleted in the destructor of that class.
That's not true. I'd like to see you creating a QAction object as a member variable... QAction is by any means similar to other QObject subclasses, if you delete a parent of QAction, the action gets deleted too. The only difference is that QAction requires a parent (thus it makes no sense to make it a member variable of another QObject).

spherrra
10th October 2011, 16:55
In Qt Ex. and Demos objects-parent (of the first level) are dynamical objects and they are not removed by "delete" in destructors. Why?

d_stranz
10th October 2011, 16:59
That's not true. I'd like to see you creating a QAction object as a member variable... QAction is by any means similar to other QObject subclasses, if you delete a parent of QAction, the action gets deleted too. The only difference is that QAction requires a parent (thus it makes no sense to make it a member variable of another QObject).

OK, you are probably right. In my MainWindow classes, I do create actions as children of this. But why does deleting them in the MainWindow destructor not cause a memory fault? If the action instances were in fact first-class children of the MainWindow instance, shouldn't they have already been deleted by the QObject system before it gets to my destructor? (Or if destruction occurs in the reverse order, shouldn't my deletes cause a fault somewhere further up the line as destructors for MainWindow's superclasses get invoked?)

And by "member variable" I meant that the member variable is a QAction *, not QAction.

If the QObject system guarantees that QAction instances are also deleted when their parent goes out of scope, that would save me a lot of otherwise useless member variables.


In Qt Ex. and Demos objects-parent (of the first level) are dynamical objects and they are not removed by "delete" in destructors. Why?

In most of the demos that I have looked at, the base object of the GUI is derived from QMainWindow or QDialog, and is allocated on the stack in the main() procedure. Any child that is created further down in the code is created as a child of this main window, and is therefore owned and and has its lifetime controlled by it.

wysota
10th October 2011, 17:11
I do create actions as children of this.
Children and members are two distinct things.

But why does deleting them in the MainWindow destructor not cause a memory fault?
Why would it?


If the action instances were in fact first-class children of the MainWindow instance, shouldn't they have already been deleted by the QObject system before it gets to my destructor?
Think what is the order of destructor calls when using C++ inheritance.


And by "member variable" I meant that the member variable is a QAction *, not QAction.
Here a pointer to an object is a member variable, not the object itself. You can have 10 pointers pointing to the same object and all these can be member variables of different objects. The pointed object doesn't have to be a member variable of any object.

d_stranz
10th October 2011, 17:29
Pardon me for using imprecise terminology. I have a bit more than 20 years of C++ experience, and I understand the differences between heap and stack allocated objects, and how pointers and references work. I do remember the order in which destructors are called but if you write semantically correct code it doesn't usually matter.

And IMO, a "member variable" can be a value that is stack-allocated during construction, a reference assigned during construction, or a pointer to a heap-allocated instance created and assigned at any time during the lifetime of an object instance. You imply that it is only the first type. If so, then what do you call a pointer variable that is defined as a member of a class if not a "member variable"?

Nomenclature aside, if I create a pointer to a QObject type using another QObject instance as its parent, store that pointer in a pointer member variable of that class, then delete that pointer in my class destructor, why doesn't that cause a memory fault? Creating that pointer and setting my class instance as its parent presumably stored it away somewhere in Qt's object hierarchy system with a flag that says, "when this parent goes out of scope, delete this child, too". So, if I delete it first, then that leaves a dangling pointer which should cause a memory fault when Qt tries to delete it later. Why not? Is the QObject constructor written in such a way that deleting a QObject instance also removes it from any parent-child relationship it might be in?

If this is true, then is there ever a case in Qt where a call to delete is required, except at the very top of a heap-allocated object hierarchy?

spherrra
10th October 2011, 17:44
For example: Qt 4.7 Examles and Demos, OpenGL, Hello GL Example

There are two classes GLWidget and Window. I cite the file window.cpp


Window::Window()
{
glWidget = new GLWidget;

The object "glWidget" is dynamical. But it is not the object-child of object of the Window. I must so writte


Window::Window()
{
glWidget = new GLWidget(this);


or writte destructor


Window::~Window()
{
delete glWidget;

But it's not in this example. Why?

d_stranz
10th October 2011, 17:59
For example: Qt 4.7 Examles and Demos, OpenGL, Hello GL Example

But it's not in this example. Why?

Look at these lines:



QHBoxLayout *mainLayout = new QHBoxLayout;
mainLayout->addWidget(glWidget);

// ...

setLayout(mainLayout);


This first line creates a QHBoxLayout. The second line assigns it as the parent of glWidget. The third line assigns Window as the parent of mainLayout. So, mainLayout is owned by Window, and glWidget is owned by mainLayout. Each of these children will be deleted automatically when Window goes out of scope.

spherrra
10th October 2011, 18:19
Ok. Thank you! I understood this. Спасибо :)

wysota
10th October 2011, 18:33
And IMO, a "member variable" can be a value that is stack-allocated during construction, a reference assigned during construction, or a pointer to a heap-allocated instance created and assigned at any time during the lifetime of an object instance. You imply that it is only the first type. If so, then what do you call a pointer variable that is defined as a member of a class if not a "member variable"?
I didn't say anything like that. I said the pointer is a member variable and not the object it points to. If you have "int *x" then the variable which is a memeber of the object that contains it is "x" and not "*x".


Nomenclature aside, if I create a pointer to a QObject type using another QObject instance as its parent, store that pointer in a pointer member variable of that class, then delete that pointer in my class destructor, why doesn't that cause a memory fault?
Because QObject destructor is called after your destructor and the object you delete has time to detach itself from its parent and thus is not deleted again when the parent is deleted. The code is equivalent to:


QObject::~QObject() { qDeleteAll(children); setParent(0); }
void QObject::setParent(QObject *newParent) {
if(parent()) parent()->children().remove(this); // of course ignoring that children() returns a copy
m_parent = newParent;
if(m_parent) m_parent->children().append(this); // of course ignoring that children() returns a copy
}


If this is true, then is there ever a case in Qt where a call to delete is required, except at the very top of a heap-allocated object hierarchy?
A call to delete is only required if a QObject-derived (and heap allocated) object has no parent (and is not assigned to some kind of smart pointer). I usually have 0 QObject-related "delete" calls in my programs :)

Oh... one more thing. Never create QObjects with a parent on the stack (unless they are modal QDialogs which is usually safe). Then you can have double deletions (the behaviour is compiler-dependent).

Added after 8 minutes:


This first line creates a QHBoxLayout. The second line assigns it as the parent of glWidget. The third line assigns Window as the parent of mainLayout. So, mainLayout is owned by Window, and glWidget is owned by mainLayout. Each of these children will be deleted automatically when Window goes out of scope.

To be exact:


#include <QtGui>

int main(int argc, char **argv){
QApplication app(argc, argv);
QWidget *w = new QWidget;
QHBoxLayout *l = new QHBoxLayout;
l->addWidget(w);
qDebug() << ( w->parent() ? w->parent()->metaObject()->className() : "no parent");
QDialog dlg;
dlg.setLayout(l);
qDebug() << ( w->parent() ? w->parent()->metaObject()->className() : "no parent");
qDebug() << ( l->parent() ? l->parent()->metaObject()->className() : "no parent");
return 0;
}

yields:


no parent
QDialog
QDialog

The child widget is reparented to the widget and not to the layout.

d_stranz
10th October 2011, 18:37
QObject::~QObject() { qDeleteAll(children); setParent(0); }
void QObject::setParent(QObject *newParent) {
if(parent()) parent()->children().remove(this); // of course ignoring that children() returns a copy
m_parent = newParent;
if(m_parent) m_parent->children().append(this); // of course ignoring that children() returns a copy
}

OK, thanks. This is exactly what I was referring to when I asked if deleting a child removed it from its parent's list of children. So my "extra" deletes do no harm (but don't do much good, either). Away with them!


The child widget is reparented to the widget and not to the layout.

Ok, I had known that also, but was trying to keep the explanation more simple.

wysota
10th October 2011, 18:45
Ok, I had known that also, but was trying to keep the explanation more simple.

Sure, but in two years from now somebody would put the following post right under yours:


Hi d_stranz, so glad I have found this forum!

I'm a newbie in Qt and a newbie in C++. I have written the following code:


int main(...) {
QHBoxLayout *l = new QHBoxLayout;
QWidget *w = new QWidget;
l->addWidget(w);
delete l;
}

According to what you have said when "l" is deleted, it should delete "w" but it doesn't! I'm using Qt 5.2.7. Is this a bug in Qt? Should I report it to <whoever owns Qt in two years>?

d_stranz
10th October 2011, 18:55
Point taken.


<whoever owns Qt in two years>

That'll be either Google or Microsoft. (or maybe Oracle... no, Ellison couldn't be that greedy).

wysota
10th October 2011, 20:06
Or /dev/null. Certainly not Oracle.