C++ 移动语义和窗口句柄。删除对象安全句柄?
Windows中是否存在某种空句柄?如果我通过C++ 移动语义和窗口句柄。删除对象安全句柄?,c++,windows,bitmap,move-semantics,C++,Windows,Bitmap,Move Semantics,Windows中是否存在某种空句柄?如果我通过CreateCompatibleBitmap()创建bmp,并通过DeleteObject()删除它,并希望使用移动语义,我希望确保位图不会被破坏。因此,我必须将HBITMAP设置为可安全删除的值。与删除空指针类似,0通常是无效句柄,类似于空指针 例如,CreateBitmap如果失败,则返回0作为无效的位图句柄 因此,您可以使用空句柄安全地调用DeleteObject 从: 如果指定的句柄无效或当前已选择为DC,则返回值为零 例外情况是由Creat
CreateCompatibleBitmap()
创建bmp,并通过DeleteObject()
删除它,并希望使用移动语义,我希望确保位图不会被破坏。因此,我必须将HBITMAP
设置为可安全删除的值。与删除空指针类似,0通常是无效句柄,类似于空指针
例如,CreateBitmap
如果失败,则返回0作为无效的位图句柄
因此,您可以使用空句柄安全地调用DeleteObject
从:
如果指定的句柄无效或当前已选择为DC,则返回值为零
例外情况是由
CreateFile
返回的文件句柄,其中无效的句柄值定义为-1
没有这样的安全值。将有效的HGDIOBJ
以外的任何内容传递给DeleteObject
会破坏契约,并可能导致程序崩溃,特别是“逻辑笔、画笔、字体、位图、区域或调色板的句柄”。或者它可能会闯入调试器,尤其是在操作系统的已检查版本上。或者它可能会用日志消息填满你的硬盘。或者,它可能会导致AppVerifier失败并阻止徽标认证。或者,它可能会触发进程的“appcompat”规则,并“为了向后兼容”而禁用Windows的新功能。不要这样做
您可以使用0
作为占位符,但是如果句柄为0
,则测试该值,并且不要调用DeleteObject
。这与if(p)delete p相反前面的测试被认为是浪费代码。首先是坏消息。由于历史原因,Windows API中没有通常有效的“无效句柄”值。Windows中的不同子系统考虑“<代码> null <代码> >或<代码>无效IDHOLYLY值<代码>作为无效句柄值(既返回无效句柄值,又取一个无效句柄)。p>
然而,好消息是,尽管您仍然需要为意外的返回值做好准备(除非您仔细阅读您使用的每个函数的文档),但提供无效值在实践中仍然“有效”。
您可能没有使用正确的指定“无效”值,但它仍然无效,因此函数将失败。您的应用程序不会崩溃,除了浪费几个CPU周期之外,没有其他负面后果
因此,请继续使用NULL
(或nullptr
),这样做很好。如果没有其他内容,那么对于以后阅读您的代码的人来说,这是很直观的。在您的具体示例中,这也是正确的,因为GDI函数假定NULL
无效
您几乎可以相信NULL
和INVALID\u HANDLE\u VALUE
都是无效值。虽然我不知道有效的句柄必须是非零的要求(如文档中明确说明的),但实际上它们总是非零的。我敢打赌,您永远不会找到值为零的句柄(只要尝试使用Sysinternals的handle
工具,您的计算机上没有一个进程的句柄可能低于20)
但是,即使假定<代码> null <代码>可以是一个有效的句柄值,也必须考虑到一些句柄已经被打开和关闭,甚至在“代码>主< /代码>被调用或全局构造函数被运行之前,您真的没有选择。这意味着假设
NULL
可能是一个有效的句柄,并且假设它在程序运行时仍然有效,那么该假设句柄与API函数兼容的可能性非常低
另一方面,有人可能认为应用程序可能打开了(unsigned)-1
句柄,从而使无效的句柄值
成为有效值
除非你正在泄漏句柄,否则我无法想象你怎么会得到那么多打开的句柄。但更重要的是,在达到这个数字之前,您可能会在64位系统上耗尽内存,在32位系统上肯定会耗尽地址空间。
如果INVALID\u HANDLE\u VALUE
作为一个有效的句柄曾经成为一个问题,那么您就有了一个更严重的问题。HBITMAP
是一个void*
,因此nullptr
是一个完全可分配的值。CreateCompatibleBitmap失败时返回NULL。所以,我认为最好是设定为nullptr@Chubsdad在C++中,包括C++ 03,在<代码> 0 和 NUL>代码>之间没有任何区别,除了后者只能通过头文件定义获得,并且它可以指定一个除<代码> int 以外的大小。但是,使用nullptr
时,需要将句柄类型定义为指针,而0
则不需要这样做。实际上,HGDIOBJ
当前是指针,但不能保证它是指针,因此使用nullptr
不是一个好主意。我认为这一行文档的目的是描述可能导致函数失败的条件,而不是保证函数在这些条件下总是安全地失败。在上下文中阅读,其目的是“如果返回值为零,则指定的句柄无效”,这并不保证函数不会引发异常或导致其他有害的副作用。在我看来,如果措辞含糊不清或可疑,最好是防御性地进行编程。@Alf:handle实现的细节(是的,我知道它是一个索引)确实控制着未定义行为的实际结果。但是,它们不会影响未定义行为的边界。即使很容易区分NULL
句柄