TN017: 終結視窗物件
這個註解,說明如何使用CWnd::PostNcDestroy方法。 如果您想要做的自訂的配置,請使用這個方法CWnd-衍生物件。 這張便箋也說明了為什麼您應該使用CWnd::DestroyWindow要終結 C++ 視窗物件,而不是delete運算子。
如果您遵循本主題中的指導方針,您必須清理的幾個問題。 這些問題可能會導致問題,例如忘記刪除/釋放的記憶體 C++,忘記釋放系統資源,如HWNDs,或釋放物件的次數過多。
問題
每個 windows 物件 (物件類別的衍生自CWnd) 表示 C++ 物件和HWND。 C + + 物件會在應用程式的堆集配置和HWNDs 由 「 視窗管理員 」 中的系統資源配置。 由於有幾種方式可以終結視窗物件,因此我們必須先提供一組規則,以避免系統資源或記憶體流失。 這些規則也必須防止物件和視窗控制代碼被摧毀一次以上。
終結視窗
以下是兩種方法允許的可以終結視窗物件:
呼叫CWnd::DestroyWindow或 Windows API DestroyWindow。
明確地刪除與delete運算子。
如為前者是到目前為止最常見的。 這種情況下會套用,即使您的程式碼不會呼叫DestroyWindow直接。 當使用者直接關閉框架視窗時,這個動作會產生WM_CLOSE訊息,以及回應這封郵件的預設值就是呼叫DestroyWindow. 當父視窗被損毀時,Windows 就會呼叫DestroyWindow的所有子系。
第二個情況、 所用的delete運算子,在視窗物件,應該相當罕見。 下列為一些狀況下,使用delete是正確的選擇。
使用 CWnd::PostNcDestroy 的自動清除
系統會終結視窗,傳送至視窗的最後一個 Windows 訊息時, WM_NCDESTROY。 預設值CWnd該訊息的處理常式是CWnd::OnNcDestroy。 OnNcDestroy將卸離HWND C++ 物件,並呼叫虛擬函式PostNcDestroy。 某些類別覆寫此函式來刪除 C++ 物件。
預設實作的CWnd::PostNcDestroy不會執行任何動作,也就是適合視窗物件的堆疊框架上配置或內嵌於其他物件。 不,這也適用於視窗物件,使其可用來在不需要任何其他物件堆積上配置。 也就是說,不適合視窗不會內嵌在其他的 C++ 物件的物件。
這些設計來單獨配置在堆積上的類別會覆寫PostNcDestroy方法,以執行delete this。 此陳述式會釋放任何與 C++ 物件相關聯的記憶體。 即使預設值CWnd解構函式呼叫DestroyWindow如果m_hWnd為非 NULL,這不會導致無限遞迴因為控點時,將會中斷連結] 和 [空值清除階段。
注意事項 |
---|
系統通常會呼叫CWnd::PostNcDestroy它處理 Windows 後WM_NCDESTROY訊息和HWND而不會再連線至 C++ 視窗物件。系統也會呼叫CWnd::PostNcDestroy中的大部分實作CWnd::Create發生失敗時呼叫。本主題中稍後說明的自動清除規則。 |
自動清除類別
下列類別並未設計為自動清除。 它們通常被內嵌在其他的 C++ 物件,或在堆疊上:
所有的標準 Windows 控制項 (CStatic, CEdit, CListBox,依此類推)。
任何子視窗直接衍生自CWnd (例如,自訂控制項)。
分隔視窗 (CSplitterWnd)。
預設控制列 (類別衍生自CControlBar,請參閱技術提示 31 啟用自動刪除的控制項列物件)。
對話方塊 (CDialog) 為強制回應對話方塊的堆疊框架上所設計。
對話方塊以外的所有標準CFindReplaceDialog。
類別精靈所建立的預設對話方塊。
下列類別是設計用的自動清除。 它們通常是由本身配置,在堆積上:
主框架視窗 (直接或間接衍生自CFrameWnd)。
檢視視窗 (直接或間接衍生自CView)。
如果您想要違反這些規則,您必須覆寫PostNcDestroy您的衍生類別中的方法。 若要加入至類別的自動清理,呼叫您的基底類別,然後執行delete this。 若要移除自動清理,從您的類別,呼叫CWnd::PostNcDestroy直接代替PostNcDestroy您的直接基底類別的方法。
若要建立非強制回應對話方塊,可以配置在堆積上是最常見的用法,變更自動清除行為。
至 [刪除的呼叫
我們建議您呼叫DestroyWindow終結視窗物件,是 C++ 方法或全域DestroyWindow API。
請不要呼叫全域DestroyWindow API 來摧毀的 MDI 子視窗。 您應該使用的虛擬方法CWnd::DestroyWindow相反的。
對於 C++ 視窗物件,並不會執行自動清理,使用delete運算子會造成記憶體遺漏,當您嘗試呼叫DestroyWindow在CWnd::~CWnd如果 VTBL 並未指向正確的衍生類別的解構函式。 這是因為系統找不到適當的損毀時要呼叫方法。 使用DestroyWindow而不是delete可以避免這些問題。 因為這可能非常難以捉摸的錯誤,在偵錯模式下編譯會產生下列警告如果您處於危險。
Warning: calling DestroyWindow in CWnd::~CWnd
OnDestroy or PostNcDestroy in derived class will not be called
如果是執行自動清理的 C++ 視窗物件,您必須呼叫DestroyWindow。 如果您使用delete運算子直接,MFC 診斷記憶體配置器會通知您您會釋放記憶體兩次。 兩個是您第一次的明確呼叫和間接呼叫delete this的自動清除實作PostNcDestroy。
在撥號後DestroyWindow非自動清除,在物件上的 C++ 物件仍然會,但是m_hWnd會是 NULL。 在撥號後DestroyWindow自動清理物件,C++ 物件就會消失不見,釋放 C++ delete 運算子,自動清理實作PostNcDestroy。