Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
663 views
in Technique[技术] by (71.8m points)

c++ - Destruction of QObjects

My program sometimes gives Segmentation Fault at the last statement in main function.

return a.exec();

I think problem is with order of destruction. Qt documentation says that

No QObject is deleted twice, regardless of the order of destruction.

But when I tried following code it gives segmentation fault.

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

I know when first is deleted, it deletes its children second also.

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

Should we be always careful about deleting child object?

I am downloading a file with QNetworkAccessManager, when file download is completed I want to delete Downloader object which inherits QObject to free memory. But if I delete it causes segmentation fault.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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.

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...