以下是有问题的代码:
class FullPage : public QWidget
{
Q_OBJECT
public:
explicit FullPage(const AppData* appdata, QWidget* parent = 0);
virtual void addIconWorking(IconWorking* temp);
virtual void removeIconWorking(IconWorking* temp);
...
}
class IconWorking : public QLabel
{
Q_OBJECT
public:
explicit IconWorking(FullPage* parent = 0);
virtual ~IconWorking();
...
}
IconWorking::IconWorking(FullPage* parent) : QLabel(parent)
{
...
parentPage = parent;
parentPage->addIconWorking(this);
...
}
IconWorking::~IconWorking()
{
parentPage->removeIconWorking(this); //segfault
QMessageBox::information(0, "TODO", "Reminder Message");
}
- 在调用之前标记的行segfault。(断点已命中,但函数内部的断点未命中)
- parentPage从未被删除,并且此时具有非零值
- FullPage::add/removeIconWorking(IconWorking*)不对对象本身执行任何操作;他们只是简单地从QList中添加/删除它。类似于Qt的原生对象系统,只是我想保证只有IconWorking在其中进行一些特殊处理
我缺少什么?
更新:
我根据注释添加了一些测试代码,看看parentPage是否会更改。事实并非如此。我使用的是一个新创建的变量,它在构造函数中赋值,并在析构函数中签入。
segfault消息没有指定地址。如果真的这样就好了。直接检查指针会得到一个非零值,包括原始测试和添加的测试,因此它们不为null。
我还发现,当我添加一些功能时,我会在一个完全不相关的位置获得一个新的segfault,它引用了程序中所有参数中传递的同一个FullPage实例。
假设~IconWorking()
在其parentPage被破坏时被调用,如父子关系所示:
当parentPage对象被销毁时,事情按以下顺序发生:
~FullPage()
在parentPage
实例上被调用。在那之后,parentPage就不再是一个有效的FullPage对象了- 调用
~Widget()
,留下一个QObject - 调用
~QObject()
,它会删除您的IconWorking对象(因为父子关系) - 执行
~IconWorking()
,它调用parentPage上的FullPage::removeIconWorking(),我认为它访问在步骤1中已经销毁的FullPage特定成员。(parentPage指向的对象目前只是一个有效的QObject,没有其他对象!) - Crash
为了使这种方法有效,~FullPage()必须手动删除IconWorking对象,而不是依赖于QObject父子关系。
好吧,我发现项目的另一个部分使用这种结构会很尴尬,所以我:
- 制作FullPage的QList
public
- 取消了要添加和删除的成员函数
- 让IconWorking直接操作它,因为这就是所有发生的事情
不知怎么的,这似乎修复了析构函数中的segfault,但我在一些类定义中得到了它们。(什么!?!)所以我重建了这个项目,这个问题也得到了解决。
所以我想这个故事的寓意是,如果它在做一些奇怪的事情,试着彻底重建。一个类中的更改可能需要重新编译另一个类,即使其他源实际上没有更改,QtCreator也不一定知道这一点。