破坏QObjects

Dee*_*pak 1 c++ qt

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

return a.exec();

我认为问题在于破坏的顺序.Qt文档说明了这一点

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

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

QWidget* first = new QWidget;
QWidget* second = new QWidget(first);
delete first;
delete second;
Run Code Online (Sandbox Code Playgroud)

我知道什么时候first被删除,它second也会删除它的孩子.

那么为什么文档说破坏的顺序无关紧要?

我们应该总是小心删除子对象吗?

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

Sig*_*erm 8

那么为什么文档说破坏的顺序无关紧要?

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

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

我们应该总是小心删除子对象吗?

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

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

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

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


说明

QWidget* first = new QWidget;
QWidget* second = new QWidget(first);
delete first;
delete second;
Run Code Online (Sandbox Code Playgroud)

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

如果INSIST在(再次)之后保留单独的second AND删除指针,你可以使用这样的东西(不要忘记):secondfirst#include <QPointer>

QPointer<QWidget> first = new QWidget,
    second = new QWidget(first);
delete first;
delete second;
Run Code Online (Sandbox Code Playgroud)

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

QWidget *first = new QWidget,
    *second = new QWidget(first);
delete first;//second is deleted automatically
Run Code Online (Sandbox Code Playgroud)

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

 QObject *a = new QObject();
 QObject *b = new QObject(a);
 b = new QObject(a);
 b = new QObject(a);
Run Code Online (Sandbox Code Playgroud)

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

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

QObject *a = new QObject(), *b = a;
delete a;
Run Code Online (Sandbox Code Playgroud)

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

这就是QPointers的用途:

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.
Run Code Online (Sandbox Code Playgroud)