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

The following is a single-file QWidget program.

//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();
}

The program crashes on exit. The function-call trace on crash is

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

If line A is removed then there is no crash.

I want to figure out what causes the crash, and how to use member QWidget and QLayout without having a crash. Thanks in advance.



Solution 1:[1]

While the problem is due to an attempt to free memory that wasn't allocated on the heap I don't think the QMainWindow destructor or a 'double-delete' is the culprit (as suggested elsewhere).

As well as deleting its children the QObject destructor will also remove itself from any parent's object hierarchy. In the code shown wgt is a data member of MainWindow meaning wgt's dtor will be invoked before that of the MainWindow instance. Hence, by the time ~MainWindow is invoked wgt is no longer a child and no attempt will be made to free it at that point. So that's not the issue.

Instead the real problem is the order in which the data members lb, lout and wgt are declared in the MainWindow class...

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

The widget hierarchy is...

wgt
  \_lb

and the implicit construction order...

lb
lout
wgt

meaning the order in which the dtors is invoked is...

wgt
lout
lb

Thus, when wgt destructor is called lb is still a child and wgt will attempt to free it. That's the cause of the problem in this particular case. While it can be solved by allocating the various QObjects on the heap, an alternative solution would be to simply re-order the member declarations within MainWindow to ensure the correct order of construction and destruction...

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

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 G.M.