最近遇到一個朋友,問了我一個刁鑽的問題,當你模態彈出一個窗體時,後臺把這個窗體的父類給析構了,這個時候會出現什麼樣的狀況?函數
聽到問題後我真是一臉懵逼呀!歷來沒有這麼寫過代碼。oop
隨後寫了一個簡單的測試demo,跟蹤了下Qt的源碼,得出以下結論:測試
帶着這兩個問題咱們來研究下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
int QDialog::exec() { ... QEventLoop eventLoop; d->eventLoop = &eventLoop; (void) eventLoop.exec(QEventLoop::DialogExec); ... }
當咱們調用QDialog的exec方法時,內部開啓了一個QEventLoop事件循環對象
int QDialog::exec() { ... while (!d->exit.loadAcquire()) processEvents(flags | WaitForMoreEvents | EventLoopExec); ... }
這個方法裏邊就是一直死循環處理咱們的事件,當d->exit.loadAcquire()返回不爲false時,事件循環退出,也就是咱們的模態窗體要關閉了。接口
下面咱們來分析d->exit.loadAcquire()這個接口爲何返回了真事件
首先我給全部調用d->exit.storeRelease方法的地方都打了斷點,發現是在QEventLoop::exit函數中命中斷點,看了下調用堆棧,沒毛病,一切正常。源碼