QT关于Qt::WA_DeleteOnClose的使用问题

Posted theArcticOcean

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了QT关于Qt::WA_DeleteOnClose的使用问题相关的知识,希望对你有一定的参考价值。

今天在解决软件bug的过程中,注意到QT关于[slot] bool QWidget::close()有这样一段说明:

If the widget has the Qt::WA_DeleteOnClose flag, the widget is also deleted. A close events is delivered to the widget no matter if the widget is visible or not.

逆向思考,如果我的QWidget或继承于QWidget的派生类没有设置相关的flag:Qt::WA_DeleteOnClose,那么他是不会自动析构的。情况真是如此吗?

测试环境:
macOS Mojave 10.14
Qt Creator 4.41
Qt 5.9.2
Clang 7.0 apple, 64 bits

场景一: 独立widget,没有flag Qt::WA_DeleteOnClose

widget.cpp

#include "widget.h"
#include "ui_widget.h"

#include <QDebug>

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)

    ui->setupUi(this);


Widget::~Widget()

    delete ui;
    qDebug() << "Widget::~Widget()";


void Widget::on_pushButton_clicked()

    close(); //output: Widget::~Widget()

main.cpp

#include "widget.h"
#include <QApplication>

int main(int argc, char *argv[])

    QApplication a(argc, argv);
    Widget w;
    w.show();

    return a.exec();

widget.ui:

在这种情况下,不设置flag QT::WA_DeleteOnClose,我们依然可用通过函数链:Widget::on_pushButton_clicked => Widget::close 来触发析构函数。
那么QT关于此flag的说明到底是什么意思呢?接着看下面的场景。

场景二: 自定义的widget作为其他widget的child widget,没有flag Qt::WA_DeleteOnClose

现在widget.ui文件设置成这样:

main.cpp

#include "widget.h"
#include <QApplication>

int main(int argc, char *argv[])

    QApplication a(argc, argv);
    QWidget parentW;
    parentW.show();

    Widget w(&parentW);
    w.show();
    setbuf( stdout, NULL );
    return a.exec();

qwidget.cpp

#include "widget.h"
#include "ui_widget.h"

#include <QDebug>

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)

    ui->setupUi(this);

    printf( "this: %p\\n", this );
    printf( "ui: %p\\n", ui );


Widget::~Widget()

    delete ui;
    qDebug() << "Widget::~Widget()";


void Widget::on_pushButton_clicked()

    qDebug() << testAttribute( Qt::WA_DeleteOnClose );
    close();

一开始显示:

然后我们点击button,button消失。输出:

this: 0x7ffeed17e9e0
ui: 0x7faaacd12c40
false

析构函数没有被调用。

场景三: 自定义的widget作为其他widget的child widget,有flag Qt::WA_DeleteOnClose

在场景二的基础上,Widget的构造函数中加上:

setAttribute( Qt::WA_DeleteOnClose, true );

运行,再点击button,我们得到:

this: 0x7ffee5578a28
ui: 0x7fc99ef14f70
true
Widget::~Widget()
The program has unexpectedly finished.
The process was ended forcefully.

系统报错:error for object 0x7ffee5578a28: pointer being freed was not allocated
也就说,函数链:Widget::on_pushButton_clicked => Widget::close触发了一次析构函数,后面widget的对象又被析构了一次。
注意到我们的Widget对象在main.cpp中是分配到栈内存的,所以在main函数结束后,系统会尝试析构我们的Widget对象。
在qwidget.cpp我们能找到这样的语句:

8442      if (!that.isNull()) 
8443           data.is_closing = 0;
8444           if (q->testAttribute(Qt::WA_DeleteOnClose)) 
8445              q->setAttribute(Qt::WA_DeleteOnClose, false);
8446              q->deleteLater();
8447           
8448      
8449      return true;
8450 

接着,将Widget对象从堆里申请内存,就不会存在多次释放内存的问题了。
main.cpp

Widget *w = new Widget(&parentW);
w->show();

点击红色的button之后:

总结:Qt::WA_DeleteOnClose用于申请堆内存的QWidget对象,并有通过close方法释放内存的需求的场景。

以上是关于QT关于Qt::WA_DeleteOnClose的使用问题的主要内容,如果未能解决你的问题,请参考以下文章

Qt的模态对话框和非模态对话框 经常使用setAttribute (Qt::WA_DeleteOnClose)

QT学习_Menu菜单

QT学习_Menu菜单

QT学习_Menu菜单

QT 控件内存管理

Qt窗口及控件-窗口Close()自动释放