TN017:销毁的窗口对象
此说明描述了使用 CWnd::PostNcDestroy 方法。 ,如果要执行 CWnd的自定义的分配派生的对象,请使用此方法。 此说明还解释为何应使用 CWnd::DestroyWindow 销毁 c. C++ windows 对象而不是 delete 运算符。
如果您遵循本主题中的准则,您将具有很少清理问题。 这些问题可能是由于等问题忘记删除/自由 C++ 内存,忘记释放与 HWND中的系统资源或释放对象多次。
问题
每个窗口对象 (从 CWnd派生的类的对象) 表示 c. C++ 对象和 HWND。 C++ 对象在应用程序内存段分配,并 HWNDs 在系统资源分配由 windows 管理器。 由于有多种方式销毁窗口对象,必须提供防止系统资源或内存泄漏的规则集。 这些规则还必须防止对象和窗口句柄销毁超过一次。
销毁的窗口
下面是两个允许的方式销毁窗口对象:
调用 CWnd::DestroyWindow 或 windows API DestroyWindow。
显式删除与 delete 运算符。
第一种情况是迄今为止最常见的。 此种情况下应用,即使您的代码不直接调用 DestroyWindow 。 当用户直接关闭了框架窗口时,此操作将生成 WM_CLOSE 消息,并且,到此消息的默认响应是调用 DestroyWindow.,当销毁时父窗口,这些窗口调用其所有子级 DestroyWindow 。
第二种情况下,使用窗口对象的 delete 运算符,应该很少见。 以下是使用 delete 的情形是正确的选择。
与 CWnd::PostNcDestroy 的自动清理
当系统销毁一个窗口时,最后一个窗口发送到窗口是 WM_NCDESTROY。 该消息的默认 CWnd 处理程序是 CWnd::OnNcDestroy。 OnNcDestroy 将分离 C++ 对象的 HWND 并调用虚函数 PostNcDestroy。 这些类重写此函数删除 C++ 对象。
CWnd::PostNcDestroy 的默认实现不执行任何操作,为 windows 对象适用于堆栈帧在其他对象分配或中。 对于堆中分配模型中,不包含任何其他对象的 windows 对象不正确。 换言之,用于其他 C++ 对象不会嵌入的 windows 对象不正确。
在堆重写旨在单独分配执行 delete this的 PostNcDestroy 方法的某些类。 此语句将释放所有内存与 C++ 对象。 即使默认 CWnd 调用析构函数 DestroyWindow ,如果 m_hWnd 非 null,则不会导致无限递归,因为在处理清理阶段将是分立和空。
备注
该系统通常称为 CWnd::PostNcDestroy ,在处理 windows WM_NCDESTROY 消息后,并 HWND 和 C++ windows 对象不再连接。,如果失败,系统还将调用在大多数 CWnd::Create 的实现的 CWnd::PostNcDestroy 调用。自动清理规则本主题后面所述。
自动清理类
下面的类不用于自动清理模型。 它们通常嵌入其他 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++ 不执行自动清理的 windows 对象,使用 delete 运算符可导致内存泄漏,当您尝试调用 CWnd::~CWnd 析构函数中 DestroyWindow ,如果通信不指向正确派生类。 ,因为系统无法找到销毁方法的适当调用,则发生。 使用而不是 delete 的 DestroyWindow 避免这些问题。 由于这是一种细微错误,在调试模式下编译则将生成以下警告,则是危险的。
Warning: calling DestroyWindow in CWnd::~CWnd
OnDestroy or PostNcDestroy in derived class will not be called
对于 C++ 执行自动清理的 windows 对象,必须调用 DestroyWindow。 如果直接使用 delete 运算符, MFC 诊断内存分配器将通知您释放内存两次。 两个 byte 是在首次的显式调用,并间接调用 PostNcDestroy的自动清理实现的 delete this 。
在调用非自动清理对象的 DestroyWindow 后, C++ 对象,但是, m_hWnd 将为空。 在调用自动清理对象的 DestroyWindow 后, C++ 对象将在其中,释放由 PostNcDestroy的自动清理实现的 C++ 删除运算符。