考虑以下代码片段:
// MyWindow.h
struct MyWindow
{
LRESULT CALLBACK myWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
static LRESULT CALLBACK myWindowProcWrapper(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
};
extern MyWindow *windowPtr; // windowPtr is initialized on startup using raw new
// MyWindow.cpp
MyWindow *windowPtr = 0;
LRESULT CALLBACK MyWindow::myWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_NCDESTROY:
delete windowPtr;
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
LRESULT CALLBACK MyWindow::myWindowProcWrapper(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
return windowPtr->myWindowProc(hwnd, msg, wParam, lParam);
}
问题是给定的代码片段是否像编写的那样安全。
基本上,MyWindow
是使用 WinAPI 创建的窗口的类。当窗口被销毁时,我需要做一些最后的清理工作。
请注意,MyWindow
的实例 windowPtr
是使用原始 new
创建的。我必须删除成员函数中某处的实例,因此我从成员函数中删除了对对象本身的引用。
代码依赖于 WM_NCDESTROY
是该窗口收到的最后一条消息的假设。
所以问题如下:
- 假设
WM_NCDESTROY
始终是窗口收到的最后一条消息并在那里执行最终清理是否安全? - 列出的代码安全吗?如果不是,它会在什么条件下破裂?
备注:我只对代码在技术上是否安全感兴趣,而不是使用原始新变量和/或全局变量是否是一种好的做法。我有一些很好的理由来实现这种做法。
最佳答案
没有明确记录,WM_NCDESTROY
是窗口收到的最终消息。不过,如果您仔细阅读两行之间的内容,则可以推断出此信息。
WM_NCDESTROY 的文档包含以下备注:
This message frees any memory internally allocated for the window.
Window Features: Window Destruction概述了这样做的后果:
When a window is destroyed, the system [...] removes any internal data associated with the window. This invalidates the window handle, which can no longer be used by the application.
将它们放在一起,销毁窗口会使其窗口句柄无效。一旦 WM_NCDESTROY
消息处理程序运行完成,窗口句柄就不再有效。无效的窗口句柄不再接收任何消息。
因此您的实现是安全的。
这些规则中的任何一条在未来是否会发生变化是值得怀疑的(有这么多应用程序依赖于 WM_NCDESTROY
作为最终消息),但是如果你想做好准备,你可能需要考虑在 delete windowPtr;
之后放置一个 windowPtr = nullptr;
语句。这样做可以确保您的应用程序以可预测的方式失败,以防它在处理 MyWindow
实例后收到消息。
关于c++ - 在 WM_NCDESTROY 上释放自己安全吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41362469/