使用带有自定义删除器的shared_ptr使HANDLE RAII兼容
我最近在 SO 上发布了有关 RAII 的一般问题。 但是,我的 HANDLE 示例仍然存在一些实现问题。
HANDLE
在 windows.h
中被类型定义为 void *
。因此,正确的 shared_ptr
定义必须是
std::tr1::shared_ptr<void> myHandle (INVALID_HANDLE_VALUE, CloseHandle);
示例 1 CreateToolhelp32Snapshot
:返回 HANDLE
并有效。
const std::tr1::shared_ptr<void> h
(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL), CloseHandle);
当我在定义中使用 void
(正确的方法是什么?)时,当我尝试使用此指针调用更多 winapi 命令时,问题仍在继续。它们功能正常,但很丑,我确信必须有更好的解决方案。
在以下示例中,h
是通过顶部定义创建的指针。
示例 2 OpenProcessToken
:最后一个参数是 PHANDLE
。与演员阵容中等丑陋。
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
(PHANDLE)&h);
示例 3 Process32First
:第一个参数是 HANDLE
。真的很难看。
Process32First(*((PHANDLE)&h), &pEntry);
示例 4 与常量 HANDLE
的简单比较。真的很难看。
if (*((PHANDLE)&h) == INVALID_HANDLE) { /* do something */ }
为 HANDLE 创建正确的共享指针的正确方法是什么?
I've recently posted a general question about RAII at SO.
However, I still have some implementation issues with my HANDLE example.
A HANDLE
is typedeffed to void *
in windows.h
. Therefore, the correct shared_ptr
definition needs to be
std::tr1::shared_ptr<void> myHandle (INVALID_HANDLE_VALUE, CloseHandle);
Example 1 CreateToolhelp32Snapshot
: returns HANDLE
and works.
const std::tr1::shared_ptr<void> h
(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL), CloseHandle);
As I use void
in the definition (what is the correct way?) problems go on, when I try to call some more winapi commands with this pointer. They functionally work, but are ugly and I am sure that there has to be a better solution.
In the following examples, h
is a pointer which was created via the definition at the top.
Example 2 OpenProcessToken
: last argument is a PHANDLE
. medium ugly with the cast.
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
(PHANDLE)&h);
Example 3 Process32First
: first argument is a HANDLE
. REALLY ugly.
Process32First(*((PHANDLE)&h), &pEntry);
Example 4 simple comparison with a constant HANDLE
. REALLY ugly.
if (*((PHANDLE)&h) == INVALID_HANDLE) { /* do something */ }
What is the correct way to create a proper shared_ptr for a HANDLE?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
示例 1 正确,
示例 2 错误。通过盲目转换为 PHANDLE,shared_ptr 逻辑被绕过。它应该是这样的:
或者,分配给预先存在的shared_ptr:
或者,创建您自己的、安全的OpenProcessToken版本,它返回一个共享句柄而不是获取PHANDLE:
示例3:不需要走这些弯路。这应该没问题:
示例 4:同样,不要绕道:
为了让事情变得更好,您可以输入类似以下内容的 typedef:
或者更好的是,如果要使用 CloseHandle() 关闭所有句柄,请创建一个包含 Shared_ptr 的 SharedHandle 类并自动提供正确的删除器:
Example 1 is OK
Example 2 is wrong. By blindly casting to PHANDLE, the shared_ptr logic is bypassed. It should be something like this instead:
or, to assign to a pre-exising shared_ptr:
or, create your own, safe, version of OpenProcessToken that returns a shared handle instead of taking a PHANDLE:
Example 3: No need to take these detours. This should be ok:
Example 4: Again, no detour:
To make things nicer, you could typedef something like:
or better yet, if all handles are to be closed with CloseHandle(), create a SharedHandle class wrapping a shared_ptr and automatically providing the right deleter:
不要为此而烦恼shared_ptr,使用ATL::CHandle。
原因如下:
CHandle
时,您就知道它是句柄的 RAII 包装器。shared_ptr
时,您不知道它是什么。CHandle
不会共享所有权(但是在某些情况下您可能需要共享所有权)。CHandle
是 Windows 开发堆栈的标准。CHandle
比带有自定义删除器的shared_ptr
更紧凑(更少的打字/读取)。Don't bother with shared_ptr for that, use ATL::CHandle.
Here is why:
CHandle
you know that it's a RAII wrapper for a handle.shared_ptr<void>
you don't know what it is.CHandle
doesn't make an ownership shared (however in some cases you may want a shared ownership).CHandle
is a standard for a windows development stack.CHandle
is more compact thanshared_ptr<void>
with custom deleter (less typing/reading).看一下 boost 2:shared_ptr 包装资源句柄
Take a look at boost 2: shared_ptr wraps resource handles
这是我的替代方案,这非常好,除了您需要始终在
.get()
之后取消引用并且需要函子或 lambda:然后:
我最喜欢的是没有额外的工作要做访问它:
当然,辅助函数适用于任何类似的句柄类型。
Here is my alternative, which is quite nice except you need to dereference always after
.get()
and requires a functor or lambda:then:
what I like most about this is there is no extra work to have access to this:
and of course, the helper function works with any handle type of the likes.