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?
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.
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).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:
Take a look at boost 2: shared_ptr wraps resource handles