调用成员->函数(this);在析构函数中导致段错误
Calling member->function(this); in Destructor causes Segfault
这是有问题的代码:
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");
}
- 调用前标记的行段错误。 (断点命中,但函数内的断点未命中)
- parentPage 从未被删除,此时具有非零值。
- FullPage::add/removeIconWorking(IconWorking*) 不对对象本身做任何事情;他们只是 add/remove 它来自 QList。类似于 Qt 的本机对象系统,除了我想保证只有 IconWorking 在那里进行一些特殊处理。
我错过了什么?
更新:
我根据评论添加了一些测试代码,以查看 parentPage 是否发生过更改。它没有。我正在使用在构造函数中分配并在析构函数中检查的新创建的变量。
段错误消息未指定地址。如果它这样做会很好。直接检查指针给出了一个非零值,包括原始和添加的测试,所以它们不是空的。
我还发现,当我添加一些功能时,我在一个完全不相关的位置得到了一个新的段错误,它引用了在整个程序的参数中传递的同一个 FullPage 实例。
假设 ~IconWorking()
在其 parentPage 被销毁时被调用,如父子关系所示:
当 parentPage 对象被销毁时,事情会按以下顺序发生:
~FullPage()
在 parentPage
实例上调用。之后,parentPage 不再是有效的 FullPage 对象!
~Widget()
被调用,留下一个QObject。
~QObject()
被调用,它删除了你的 IconWorking 对象(因为父子关系)
~IconWorking()
被执行,它在 parentPage 上调用 FullPage::removeIconWorking(),我假设,它访问已在步骤 1 中销毁的 FullPage-specific 成员。(parentPage 指向的对象位于这一点只有一个有效的QObject,没有别的!)
- 崩溃
要使这种方法起作用,~FullPage() 必须手动删除 IconWorking 对象,而不是依赖于 QObject 父子关系。
好吧,我发现项目的另一个部分使用该结构会很尴尬,所以我:
- 制作了 FullPage 的 QList
public
。
- 取消了要添加和删除的成员函数。
- 如果 IconWorking 直接操作它,因为这就是所有发生的事情。
不知何故,这似乎修复了析构函数中的段错误,但我在某些 class 定义本身上得到了它们。 (什么!?!)所以我重建了项目,这也被修复了。
所以我想这个故事的寓意是,如果它做了一些奇怪的事情,请尝试完全重建。一个 class 中的更改可能需要重新编译另一个,即使另一个源实际上没有更改,Qt Creator 不一定知道这一点。
这是有问题的代码:
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");
}
- 调用前标记的行段错误。 (断点命中,但函数内的断点未命中)
- parentPage 从未被删除,此时具有非零值。
- FullPage::add/removeIconWorking(IconWorking*) 不对对象本身做任何事情;他们只是 add/remove 它来自 QList。类似于 Qt 的本机对象系统,除了我想保证只有 IconWorking 在那里进行一些特殊处理。
我错过了什么?
更新:
我根据评论添加了一些测试代码,以查看 parentPage 是否发生过更改。它没有。我正在使用在构造函数中分配并在析构函数中检查的新创建的变量。
段错误消息未指定地址。如果它这样做会很好。直接检查指针给出了一个非零值,包括原始和添加的测试,所以它们不是空的。
我还发现,当我添加一些功能时,我在一个完全不相关的位置得到了一个新的段错误,它引用了在整个程序的参数中传递的同一个 FullPage 实例。
假设 ~IconWorking()
在其 parentPage 被销毁时被调用,如父子关系所示:
当 parentPage 对象被销毁时,事情会按以下顺序发生:
~FullPage()
在parentPage
实例上调用。之后,parentPage 不再是有效的 FullPage 对象!~Widget()
被调用,留下一个QObject。~QObject()
被调用,它删除了你的 IconWorking 对象(因为父子关系)~IconWorking()
被执行,它在 parentPage 上调用 FullPage::removeIconWorking(),我假设,它访问已在步骤 1 中销毁的 FullPage-specific 成员。(parentPage 指向的对象位于这一点只有一个有效的QObject,没有别的!)- 崩溃
要使这种方法起作用,~FullPage() 必须手动删除 IconWorking 对象,而不是依赖于 QObject 父子关系。
好吧,我发现项目的另一个部分使用该结构会很尴尬,所以我:
- 制作了 FullPage 的 QList
public
。 - 取消了要添加和删除的成员函数。
- 如果 IconWorking 直接操作它,因为这就是所有发生的事情。
不知何故,这似乎修复了析构函数中的段错误,但我在某些 class 定义本身上得到了它们。 (什么!?!)所以我重建了项目,这也被修复了。
所以我想这个故事的寓意是,如果它做了一些奇怪的事情,请尝试完全重建。一个 class 中的更改可能需要重新编译另一个,即使另一个源实际上没有更改,Qt Creator 不一定知道这一点。