MFC 销毁Windows对象需要注意的问题
<reference : MFC TNO 17>
文档介绍如何使用 CWnd::PostNcDestroy()的使用方法
MFC中用C++对象来封装一个Window对象,这样需要注意一些重要的问题:
销毁一个C++封装的Window对象必须用DestroyWindow而不是delete
问题:
MFC中Window对象(指从CWnd对象中派生的新对象)同时代表着一个C++对象(在应用程序堆Heap上分配)和一个句柄(windows管理器在系统资源中分配) 所以必须要定义销毁Windows对象的方法约束: 来预防内存泄露和系统资源未回收 抑或 内存和系统资源被多次释放;
因为这不仅仅只是内存管理的问题,Windows中的窗体是与界面相关的,所以它同时关联一些的资源,系统资源的管理问题比应用程序的内存管理带来的问题往往会更加严重。
销毁Windows对象
有2种可行的方案来销毁一个windows 对象:
1 调用CWnd::DestroyWindow()或Windows API DestroyWindow()
2 显式的调用delete操作符
第一种方法迄今为止是最通用的方法,甚至于代码中不直接调用,如在程序中关闭窗体时的
WM_CLOSE消息处理的默认行为,Frame关闭时同时会调用DestroyWindow来销毁所有的子窗体;
第二种方法用delete对象来销毁一个Window Object是很少用到,只限于以下提及的几种:
当销毁一个Windows 窗体,最后一个发送给窗体的消息是WM_NCDESTROY 默认的CWnd处理该消息的方法为CWnd::OnNcDestroy() 会将句柄与C++对象分离,然后调用虚函数PostNcDestroy() 一些类会重载这个方法来delete C++对象
默认的CWnd::PosNcDestroy()的行为不作出任何方式的处理,这适用于那些在栈(stack)上分配的内存和内嵌(embedded)于其它的C++对象的Windows对象; 但是对于那些在堆上分配的Windows对象这种默认的处理方式则不适用(不包括那些内嵌的对象)
这些在堆上分配的Windows对象需要在重载PosNcDestroy()并在其中delete this;这样才可以完全释放关联在C++对象上的内存 尽管默认的window对象在其析构函数中会在m_hwnd不是空值NULL时调用DestroyWindow但是这不会形成循环递归调用 应为在清除时句柄会脱离掉(detach)并被设为空值
注意:
一般CWnd::PostNcDestroy会在WM_NCDESTROY消息处理之后调用,但是默认的在构造窗体
Create()函数调用失败以后 仍然会调用CWnd::PostNcDestroy()
MFC中需要自动清理的类(Auto Cleanup Classes)
以下为不需要自动清理的MFC类:
1 标准windows控件(CStatic CEdit CListBox etc)
2 所有直接从CWnd中派生的子窗体 (如自定义控件)
3 切分窗体(CSplitterWnd)
4 default control bar
5 对话框
6 全部的标准对话框(如CFileDialog CColorDialgo) 除了CFindReplaceDialog
7 所有由ClassWizard派生的对话框
以下的为需要自动清理的MFC类 它们一般分配在堆上:
1 Main Frame Windows 一般直接从CFrameWnd中派生的类
2 View windows 直接或间接从CView中派生的类
如果在程序设计中需要打破以上的约定,那么就需要在PostNcDestroy中做出相应的处理
最常见莫过于 在堆上分配一个无模式对话框;