下面是一个单文件的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
析构函数或“双重删除” ' 是罪魁祸首(如其他地方所建议的那样)。
QObject
析构函数除了删除它的子对象外,还将把它自己从任何父对象的对象层次结构中删除。在显示的代码中,wgt
是 MainWindow
的数据成员,这意味着 wgt
的 dtor 将在 MainWindow的 dtor 之前被调用
实例。因此,当 ~MainWindow
被调用时,wgt
不再是一个 child ,此时不会尝试释放它。所以这不是问题。
相反,真正的问题是数据成员 lb
、lout
和 wgt
在 MainWindow< 中声明的顺序
类...
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
来解决,但另一种解决方案是简单地重新排序 MainWindow
中的成员声明,以确保正确的顺序 build 与破坏……
class MainWindow: public QMainWindow {
QWidget wgt;
QVBoxLayout lout{&wgt};
QLabel lb;
关于c++ - 带有成员 QWidget 和 QLayout 的 QMainWindow 在退出时崩溃,如何解决?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71882880/