Qt疑難問題-模態窗口父類被析構

最近遇到一個朋友,問了我一個刁鑽的問題,當你模態彈出一個窗體時,後臺把這個窗體的父類給析構了,這個時候會出現什麼樣的狀況?函數

聽到問題後我真是一臉懵逼呀!歷來沒有這麼寫過代碼。oop

隨後寫了一個簡單的測試demo,跟蹤了下Qt的源碼,得出以下結論:測試

  1. 首先程序不會崩潰
  2. 模態窗口會被析構並關閉

帶着這兩個問題咱們來研究下Qt的代碼ui

一、測試代碼

測試代碼超級簡單,就是當咱們的模態窗體彈出時,使用定時器10s後析構了其父類obj對象this

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

二、堆棧調用

首先咱們來看下模態窗口析構時,是由誰觸發的,以下圖所示,從堆棧能夠很清楚的看到是父類按鈕析構時,析構其全部子窗口乾的。code

三、分析代碼

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函數中命中斷點,看了下調用堆棧,沒毛病,一切正常。源碼

相關文章
相關標籤/搜索