带有成员 QWidget 和 QLayout 的 QMainWindow 在退出时崩溃,如何解决?

QMainWindow with member QWidget and QLayout crashes on exit, how to fix that?

以下为单文件QWidget程序。

//main.cpp
#include <QApplication>
#include <QMainWindow>
#include <QVBoxLayout>
#include <QLabel>
class MainWindow:public QMainWindow{
    QLabel lb;
    QWidget wgt;
    QVBoxLayout lout{&wgt};
public:
    MainWindow(){
        lout.addWidget(&lb);//line A
        setCentralWidget(&wgt);
    }
};
int main(int argc, char *argv[]){
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

程序在退出时崩溃。崩溃时的函数调用跟踪是

system calls
QObjectPrivate::deleteChildren()
QWidget::~QWidget()
QMainWindow::~MainWindow
main

如果删除 A 行,则不会发生崩溃。

我想弄清楚导致崩溃的原因,以及如何在不崩溃的情况下使用成员 QWidget 和 QLayout。提前致谢。

虽然问题 由于试图释放未在堆上分配的内存,但我认为 QMainWindow 析构函数或 'double-delete' 是罪魁祸首(如其他地方所建议)。

除了删除它的 children 之外,QObject 析构函数也会从任何 parent 的 object 层次结构中删除自己。在显示的代码中,wgtMainWindow 的数据成员,这意味着 wgt 的 dtor 将在 MainWindow 实例的 dtor 之前被调用。因此,在 ~MainWindow 被调用时 wgt 不再是 child 并且此时不会尝试释放它。所以这不是问题。

相反,真正的问题是数据成员 lbloutwgtMainWindow class 中声明的顺序。 .

class MainWindow: public QMainWindow {
    QLabel      lb;
    QWidget     wgt;
    QVBoxLayout lout{&wgt};

小部件层次结构是...

wgt
  \_lb

和隐式构造顺序...

lb
lout
wgt

意味着调用 dtor 的顺序是...

wgt
lout
lb

因此,当调用 wgt 析构函数时,lb 仍然是 child 并且 wgt 将尝试释放它。这就是这个特定案例中问题的原因。虽然可以通过在堆上分配各种 QObject 来解决,但另一种解决方案是简单地 re-order MainWindow 中的成员声明,​​以确保构造和销毁的正确顺序。 ..

class MainWindow: public QMainWindow {
    QWidget     wgt;
    QVBoxLayout lout{&wgt};
    QLabel      lb;