破坏QObjects

时间:2013-07-18 17:34:33

标签: c++ qt

我的程序有时会在main函数的最后一个语句中给出Segmentation Fault。

return a.exec();

我认为问题是破坏的顺序。 Qt documentation

  

无论破坏的顺序如何,都不会删除QObject两次。

但是当我尝试使用代码时,它会给出分段错误。

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

我知道删除first后,它也会删除其子second

那么为什么文档说毁灭的顺序无关紧要?

我们应该一直小心删除子对象吗?

我正在使用QNetworkAccessManager下载文件,当文件下载完成时我想删除继承Downloader以释放内存的QObject对象。但如果我删除它会导致分段错误。

2 个答案:

答案 0 :(得分:7)

  

那么为什么文档说毁灭的顺序无关紧要?

这意味着您无需手动删除对象。 Qt将在父/子层次结构中注册对象并在必要时将其删除。

当然,它无法跟踪您可能存储在某处的所有指针。因此,如果您使用指向对象的指针,然后删除对象的父对象,然后尝试删除您所使用的指针,那将完全是您的错。

  

我们应该一直小心删除子对象吗?

没有。删除子对象时,它将从其父对象中取消注册。 如果您删除second,然后删除first,程序将正常运行。 所以你应该记住,一旦你杀了一个物体,它的所有孩子都会消失。

顺便说一下,Qt专门针对这种情况制作了QPointer类,所以你应该使用它而不是原始指针。 <{1}}当它指向的对象被销毁时将自己设置为零。

  

但如果我删除它会导致分段错误。

这意味着您的程序有一个未修复的错误。并且很可能(98%的可能性)错误在您的代码中,并且不是Qt的错。调试segfault并查看它发生的位置。


解释

QPointer

当您删除QWidget* first = new QWidget; QWidget* second = new QWidget(first); delete first; delete second; 时,它也会删除first,因为second是其子级。 但是,您的指针second不会自动更新。它将变成悬空指针(指向不再存在的对象),并尝试删除它,将触发未定义的行为,在您的情况下,将导致程序崩溃。

如果您 INSIST second之后保留second AND 删除second的单独指针(再次),你可以使用这样的东西(别忘了first):

#include <QPointer>

然而,没有真正的需要,通常人们只是这样做:

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

通常,在C ++中,您必须手动QWidget *first = new QWidget, *second = new QWidget(first); delete first;//second is deleted automatically 自己分配的每个对象(使用delete)。这很容易出错,需要你编写一个析构函数,你可能有时会忘记它,这会导致内存泄漏。 但是,QObject会自动删除其析构函数中的所有子节点,这意味着完全可以这样做:

new

只要您记得删除顶级对象,其所有子资源都将自动释放。

但是,Qt无法跟踪您存储的指针。所以如果你做这样的事情:

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

它不会更新现有的原始指针。顺便说一句,这是标准的C ++行为。

这就是QPointers的用途:

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

答案 1 :(得分:2)

Qt无法控制您是否尝试delete已被销毁的对象。 second对象被销毁时删除了first

但是,文档确实包括使用QObject::deleteLater()删除QObject的情况,这是为此案例设计的。如果您delete QWidget而不是使用此方法,我无法想到这种情况。唯一不行的是当你在事件循环之外时,在这种情况下你不应该破坏/创建小部件。