【问题标题】:Calling member->function(this); in Destructor causes Segfault调用 member->function(this);在析构函数中导致 Segfault
【发布时间】:2016-10-12 03:22:09
【问题描述】:

这是有问题的代码:

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*) 不对对象本身做任何事情;他们只是从 QList 中添加/删除它。类似于 Qt 的原生对象系统,除了我想保证只有 IconWorking 在那里进行一些特殊处理。

我错过了什么?


更新:

我为每个 cmets 添加了一些测试代码,以查看 parentPage 是否发生变化。它没有。我正在使用在构造函数中分配并在析构函数中检查的新创建的变量。

段错误消息未指定地址。如果是这样就好了。直接检查指针会给出一个非零值,包括原始测试和添加的测试,因此它们不为空。

我还发现,当我添加一些功能时,我在一个完全不相关的位置获得了一个新的段错误,它引用了在整个程序的参数中传递的同一个 FullPage 实例。

【问题讨论】:

  • 目前看不到任何问题。 parentPage 的值是否仍然有效?段错误提到了哪个地址(例如 0 与其他地址)?
  • removeIconWorking 是虚拟的,这表明 this 指向一个无效的位置,并且当程序尝试取消引用指针以访问 vtable 时发生段错误。检查 parentPage 是否不为空。
  • 在ctor中打印parentPage*parentPage,然后在dtor中再次打印,验证parentPage不变且*parentPage仍然合理。
  • 你如何调用析构函数?通过删除其父级或删除IconWorking?

标签: c++ qt segmentation-fault destructor


【解决方案1】:

假设 ~IconWorking() 在其 parentPage 被销毁时被调用,正如父子关系所暗示的那样:

当 parentPage 对象被销毁时,事情按以下顺序发生:

  1. ~FullPage()parentPage 实例上被调用。之后,parentPage 不再是有效的 FullPage 对象!
  2. ~Widget() 被调用,留下一个 QObject。
  3. ~QObject() 被调用,这会删除你的 IconWorking 对象(因为父子关系)
  4. ~IconWorking() 被执行,它在 parentPage 上调用 FullPage::removeIconWorking(),我假设它访问已在步骤 1 中销毁的特定于 FullPage 的成员。(此时 parentPage 指向的对象只是一个有效的 QObject,什么都没有否则!)
  5. 崩溃

为了使这种方法有效,~FullPage() 必须手动删除 IconWorking 对象,而不是依赖 QObject 父子关系。

【讨论】:

  • 我想我应该更清楚。在整个应用程序关闭之前,有几个 FullPages 永远不会被销毁。 IconWorkings 由这些父母创建,然后在父母幸存时随意deleted,让析构函数负责清理。
  • @AaronD: 然后请添加回溯以查看在哪个上下文中调用了 dtor
  • 等一下...实际上,我认为您说得对。那是我关闭应用程序的时候,它完全按照您的描述进行。这是我偶然测试的正常使用的例外。 +1
【解决方案2】:

嗯,我发现了项目的另一个部分,如果采用这种结构会很尴尬,所以我:

  • 制作了 FullPage 的 QList public
  • 取消了要添加和删除的成员函数。
  • 让 IconWorking 直接操作它,因为这就是发生的一切。

不知何故,这似乎修复了析构函数中的段错误,但我在一些类定义本身上得到了它们。 (什么!?!)所以我重建了项目,这也得到了修复。


所以我想这个故事的寓意是,如果它做了一些奇怪的事情,请尝试完全重建。一个类的更改可能需要重新编译另一个类,即使另一个源实际上没有更改,Qt Creator 也不一定知道这一点。

【讨论】:

    猜你喜欢
    • 2020-02-29
    • 2019-08-25
    • 2012-09-23
    • 2017-03-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多