C++

Qt疑难问题-模态窗口父类被析构


最近遇到一个朋友,问了我一个刁钻的问题,当你模态弹出一个窗体时,后台把这个窗体的父类给析构了,这个时候会出现什么样的情况?

听到问题后我真是一脸懵逼呀!从来没有这么写过代码。

随后写了一个简单的测试demo,跟踪了下Qt的源码,得出如下结论:

  1. 首先程序不会崩溃
  2. 模态窗口会被析构并关闭

带着这两个问题我们来研究下Qt的代码

1、测试代码

测试代码超级简单,就是当我们的模态窗体弹出时,使用定时器10s后析构了其父类obj对象

QPushButton * obj = new QPushButton;
QTimer::singleShot(10000, this, [&obj]() {
    delete obj;
    obj = nullptr;
});
QDialog * p = new QDialog(obj);
p->exec();

2、堆栈调用

首先我们来看下模态窗口析构时,是由谁触发的,如下图所示,从堆栈可以很清楚的看到是父类按钮析构时,析构其所有子窗口干的。

3、分析代码

a、QDialog::exec

int QDialog::exec()
{
    ...
    QEventLoop eventLoop;
    d->eventLoop = &eventLoop;
    (void) eventLoop.exec(QEventLoop::DialogExec);
    ...
}

当我们调用QDialog的exec方法时,内部开启了一个QEventLoop事件循环

b、QEventLoop::exec

int QDialog::exec()
{
    ...
    while (!d->exit.loadAcquire())
        processEvents(flags | WaitForMoreEvents | EventLoopExec);
    ...
}

这个方法里边就是一直死循环处理我们的事件,当d->exit.loadAcquire()返回不为false时,事件循环退出,也就是我们的模态窗体要关闭了。

下面我们来分析d->exit.loadAcquire()这个接口为什么返回了真

首先我给所有调用d->exit.storeRelease方法的地方都打了断点,发现是在QEventLoop::exit函数中命中断点,看了下调用堆栈,没毛病,一切正常。


作者:朝十晚八,发布于:2019/05/15
原文:https://www.cnblogs.com/swarmbees/p/10867898.html