模態對話框退出DoModal過程中需注意的陷阱


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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM