Qt疑难问题-模态窗口父类被析构
最近遇到一个朋友,问了我一个刁钻的问题,当你模态弹出一个窗体时,后台把这个窗体的父类给析构了,这个时候会出现什么样的情况?
听到问题后我真是一脸懵逼呀!从来没有这么写过代码。
随后写了一个简单的测试demo,跟踪了下Qt的源码,得出如下结论:
- 首先程序不会崩溃
- 模态窗口会被析构并关闭
带着这两个问题我们来研究下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函数中命中断点,看了下调用堆栈,没毛病,一切正常。