- 遇到問題
- 窗口ParentWnd下有一個子窗口ChildWndA,ChildWndA交互時彈出一個模態對話框ChildWndB,該模態對話框的父窗口是ParentWnd。
- 交互邏輯在ChildWndA對象的成員函數中處理。
- 當彈出對話框ChildWndB, 關閉子窗口ChildWndA, 再操作對話框使得對話框退出對話框窗口過程時,造成crash

- 出現問題的原因
- 對話框的窗口過程退出后,會返回產生對話框的函數中
- 由於交互邏輯在子窗口ChildWndA的成員函數中,當子窗口ChildWndA被關閉(即該對象被析構了),再關閉對話框時,對話框返回的成員函數中的this指針已經是一個野指針了
- 此時只要操作ChildWndA的類的成員變量或者成員函數,就會因為this是野指針而崩潰
- 解決方法
- ChildWndB的父窗口更改為ChildWndA
- 理論上在B彈出后,A無法操作(也就無法關閉)
- 添加強保護邏輯
- 在ChildWndA的窗口銷毀過程中,調用對話框ChildWndB的
CDialog::EndDialog函數后,再調用自身的DestroyWindow
- 在ChildWndA的窗口銷毀過程中,調用對話框ChildWndB的
- ChildWndB的父窗口更改為ChildWndA
- 涉及的知識點
- 模態對話框會阻塞當前代碼的堆棧
- 模態對話框使用
CDialog::DoModal進入對話框窗口過程的消息循環 - 外部使對話框窗口過程退出,需要調用它的
CDialog::EndDialog - 模態對話框的窗口過程正常退出后,會返回原先阻塞的代碼堆棧(也就是說,如果返回的代碼堆棧的this指針指向的對象已被析構,接下來使用該this指針訪問成員變量或者調用虛成員函數(為什么不包含普通成員函數,可以查閱筆者另外一篇文章《是否可以使用空對象指針調用成員函數及訪問成員變量》)極大概率會crash)
- 問題抽象與升華
- 對象的生命周期管理
- 子對象的生命周期管理應該由其父對象進行管理,而不應該由其兄弟對象進行管理
- 父對象退出時,應該清理子對象相關的資源
- 對象的生命周期管理
