c++ QMainWindow与成员QWidget和QLayout在退出时崩溃,如何修复?

amrnrhlw  于 2023-10-21  发布在  其他
关注(0)|答案(2)|浏览(159)

下面是一个单文件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();
}

程序在退出时崩溃。崩溃时的函数调用跟踪是
系统调用
QObjectPrivate::deleteChildren()
QWidget::~QWidget()
QMainWindow::~MainWindow
主要
如果A线被移除,则没有崩溃。
我想弄清楚是什么原因导致崩溃,以及如何使用成员QWidget和QLayout而不会崩溃。先谢了。

aoyhnmkz

aoyhnmkz1#

虽然这个问题 * 是 * 由于试图释放堆上没有分配的内存,但我不认为QMainWindow析构函数或“双重删除”是罪魁祸首(如其他地方所建议的)。
除了删除它的子对象,QObject析构函数也会从任何父对象的层次结构中删除它自己。在所示的代码中,wgtMainWindow的数据成员,这意味着wgt的dtor将在MainWindow示例的dtor之前被调用。因此,当~MainWindow被调用时,wgt不再是一个子节点,并且在那时不会尝试释放它。所以这不是问题所在。
相反,真实的问题是数据成员lbloutwgtMainWindow类中声明的顺序。

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

widget hierarchy是…

wgt
  \_lb

和隐含的构造顺序

lb
lout
wgt

这意味着调用dtors的顺序是...

wgt
lout
lb

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

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

41zrol4v2#

对于任何对此感兴趣的人来说,这是Qt中的一个实际错误,现在已经关闭-但没有解决:
https://bugreports.qt.io/browse/QTBUG-71545

相关问题