子窗口小部件依赖于父级依赖项时崩溃

时间:2016-02-09 18:42:07

标签: c++ qt

class MyMainWindow : public QMainWindow
{
private:
  SomeDependency someDependency;
}

class SomeWidget : public QWidget
{
public: 
  ~SomeWidget()
  {
    // Use someDependency by getting it from MyMainWindow (or having MyMainWindow pass it in)
  }
}

MyMainWindow::MyMainWindow(QWidget* parent)
: QMainWindow(parent)
{
  SomeWidget* someWidget = new SomeWidget(this);
}

我遇到了这种模式的问题。 MyMainWindow拥有SomeDependencyMyMainWindow在堆上创建一个新的SomeWidget并为其提供父this

SomeWidget的析构函数需要调用SomeDependency来执行某些操作(比如说...在依赖时从依赖项中取消注册)。当小部件正常消失时,这可以正常工作。

然而,当应用被杀时,有一个奇怪的问题。首先调用MyMainWindow析构函数。它会清理SomeDependency。接下来,调用QMainWindow析构函数。这将清理所有的孩子。它开始删除它的子节点,导致SomeWidget被销毁。 SomeWidget::~SomeWidget()然后调用SomeDependency ...但它已被销毁,因此应用程序崩溃。

我如何通过Qt父/子内存生存期规则进行游戏,但让孩子从MyMainWindow获取其依赖项?

1 个答案:

答案 0 :(得分:0)

最简单的解决方案是执行您应该一直执行的操作:不在堆上分配子窗口小部件,除非需要动态创建它们。 C ++具有明确定义的语义:m_widget将在m_dependency之前销毁。

class MyMainWindow : public QMainWindow
{
  SomeDependency m_dependency;
  SomeWidget m_widget;
};

m_widget作为父母MyMainWindow完全没问题。

或者,如果由于某种原因需要动态创建小部件:

class MyMainWindow : public QMainWindow
{
  SomeDependency m_dependency;
  QScopedPointer<SomeWidget> m_widget;
};

最后,SomeWidget可以共享SomeDependency的所有权:

class MyMainWindow : public QMainWindow
{
  QSharedPointer<SomeDependency> m_dependency;
  QScopedPointer<SomeWidget> m_widget { m_dependency };
};

class SomeWidget : public QWidget {
  QSharedPointer<SomeDependency> m_dependency;
public:
  SomeWidget(QScopedPointer<SomeDependency> dep, QWidget * parent = 0) :
    m_dependency(dep) {
    ...
  }
};

旁注:确保您确实需要QMainWindow。如果QDialog会这样做,请不要使用它。