移动语义和窗口句柄。 DeleteObject安全处理?

Windows中是否有某种NULL Handle? 如果我通过CreateCompatibleBitmap()创build一个bmp并通过DeleteObject()删除它,并想使用移动语义,我想确保位图不被破坏。 因此,我必须将HBITMAP设置为一个可以安全删除的值。 像delete nullptr

首先是坏消息。 由于历史原因,Windows API中没有一般有效的“无效句柄”值。 Windows中的不同子系统将NULLINVALID_HANDLE_VALUE视为无效句柄值(无论是否返回无效句柄值)。 关于旧新事物的相关文章 。

然而, 好消息是,尽管您仍然需要为意外的返回值做准备(除非您为每一个使用的功能挖掘文档),但在实践中提供无效的值仍然是“有效的”。
您可能没有使用正确的指定“无效”值,但它仍然是无效的,因此功能将失败。 您的应用程序不会崩溃,除了浪费了几个CPU周期之外,没有负面影响。

因此,继续使用NULL (或nullptr ),你很好。 如果没有别的,稍后有人阅读你的代码会很直观。 在具体的例子中, 这也是正确的 ,因为GDI函数假定NULL是无效的。

几乎可以依靠NULLINVALID_HANDLE_VALUE都是无效的值。 虽然我没有意识到一个要求(如在文档中明确指出的),一个有效的HANDLE必须是非零的,但实际上他们总是这样。 我敢打赌,你不会找到一个值为零的句柄(只要尝试使用Sysinternals的handle工具,在你的电脑上没有一个单独的进程可能会有一个低于20的句柄)。

但是,即使假设NULL可以是一个有效的句柄值,也不得不考虑在调用main或全局构造函数之前已经打开和关闭了一些句柄,但实际上并没有选择。 这意味着,假设NULL可以是一个有效的句柄,并且在程序运行的时候仍然有效,那么这个假设的句柄实际上是与API函数兼容的类型的机会是非常低的。

另一方面,有人可能会争辩说,应用程序可能(unsigned) -1处理打开,呈现INVALID_HANDLE_VALUE 有效的值。

除非你泄漏手柄,否则我无法想象你将如何得到那么多打开的手柄。 但更重要的是,在达到这个数字之前,你可能会在64位系统上耗尽内存,并且你将在32位系统上明确地耗尽地址空间。
如果INVALID_HANDLE_VALUE是一个有效的句柄成为问题,你有一个更严重的问题。

没有这样的安全价值。 除了一个有效的HGDIOBJ ,特别是一个“逻辑笔,画笔,字体,位图,区域或调色板的句柄”,传递给DeleteObject中断合同,并可能导致程序崩溃。 或者它可能会进入调试器,特别是在检查的操作系统版本。 或者它可以填充您的硬盘上的日志消息。 或者它可能会导致AppVerifier失败并阻止徽标认证。 或者它可能会触发您的过程的“appcompat”规则,并禁用新的Windows功能“向后兼容性”。 不要这样做。

您可以使用0作为占位符,但测试该值并且不要在您的句柄为0调用DeleteObject 。 这与if (p) delete p; ,前面的测试被认为是代码的浪费。

通常0是一个无效句柄,类似于一个空指针。

例如, CreateBitmap返回0作为无效的位图句柄,如果失败。

因此,您可以安全地使用nullhandle调用DeleteObject

DeleteObject的文档 :

如果指定的句柄无效或当前被选入DC,则返回值为零。

此例外是一个文件句柄,由CreateFile返回,其中INVALID_HANDLE_VALUE被定义为-1