Making a HANDLE RAII-compliant using shared_ptr with a custom deleter

c++, raii, winapi

Solution

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:

HANDLE h;
OpenProcessToken(...., &h);
shared_ptr<void> safe_h(h, &::CloseHandle);

or, to assign to a pre-exising shared_ptr:

shared_ptr<void> safe_h = ....
{
  HANDLE h;
  OpenProcessToken(...., &h);
  safe_h.reset(h, &::CloseHandle);
}//For extra safety, limit visibility of the naked handle

or, create your own, safe, version of OpenProcessToken that returns a shared handle instead of taking a PHANDLE:

// Using SharedHandle defined at the end of this post
SharedHandle OpenProcess(....)
{
    HANDLE h = INVALID_HANDLE_VALUE;
    ::OpenProcessToken(...., &h);
    return SharedHandle(h);
}

Example 3: No need to take these detours. This should be ok:

Process32First(h.get(), ...);

Example 4: Again, no detour:

if (h.get() == INVALID_HANDLE){...}

To make things nicer, you could typedef something like:

typedef shared_ptr<void> SharedHandle;

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:

// Warning: Not tested. For illustration purposes only
class SharedHandle
{
public:
  explicit SharedHandle(HANDLE h) : m_Handle(h, &::CloseHandle){};
  HANDLE get()const{return m_Handle.get();}

  //Expose other shared_ptr-like methods as needed
  //...

private:
  shared_ptr<void> m_Handle;
};

Problem

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?

Original source