带有成员 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 层次结构中删除自己。在显示的代码中,wgt
是 MainWindow
的数据成员,这意味着 wgt
的 dtor 将在 MainWindow
实例的 dtor 之前被调用。因此,在 ~MainWindow
被调用时 wgt
不再是 child 并且此时不会尝试释放它。所以这不是问题。
相反,真正的问题是数据成员 lb
、lout
和 wgt
在 MainWindow
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;
以下为单文件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 层次结构中删除自己。在显示的代码中,wgt
是 MainWindow
的数据成员,这意味着 wgt
的 dtor 将在 MainWindow
实例的 dtor 之前被调用。因此,在 ~MainWindow
被调用时 wgt
不再是 child 并且此时不会尝试释放它。所以这不是问题。
相反,真正的问题是数据成员 lb
、lout
和 wgt
在 MainWindow
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;