下面是一个单文件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而不会崩溃。先谢了。
2条答案
按热度按时间aoyhnmkz1#
虽然这个问题 * 是 * 由于试图释放堆上没有分配的内存,但我不认为
QMainWindow
析构函数或“双重删除”是罪魁祸首(如其他地方所建议的)。除了删除它的子对象,
QObject
析构函数也会从任何父对象的层次结构中删除它自己。在所示的代码中,wgt
是MainWindow
的数据成员,这意味着wgt
的dtor将在MainWindow
示例的dtor之前被调用。因此,当~MainWindow
被调用时,wgt
不再是一个子节点,并且在那时不会尝试释放它。所以这不是问题所在。相反,真实的问题是数据成员
lb
、lout
和wgt
在MainWindow
类中声明的顺序。widget hierarchy是…
和隐含的构造顺序
这意味着调用dtors的顺序是...
因此,当
wgt
析构函数被调用时,lb
仍然是一个子对象,wgt
将尝试释放它。这就是这个特殊案例中问题的原因。虽然它可以通过在堆上分配各种QObject
来解决,但另一种解决方案是简单地重新排序MainWindow
中的成员声明,以确保构造和销毁的正确顺序。41zrol4v2#
对于任何对此感兴趣的人来说,这是Qt中的一个实际错误,现在已经关闭-但没有解决:
https://bugreports.qt.io/browse/QTBUG-71545