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 typedeff
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 than shared_ptr<void>
with custom deleter (less typing/reading).Take a look at boost 2: shared_ptr wraps resource handles
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;
};
Here is my alternative, which is quite nice except you need to dereference always after .get()
and requires a functor or lambda:
template<typename HandleType, typename Deleter>
std::shared_ptr<HandleType> make_shared_handle(HandleType _handle, Deleter _dx)
{
return std::shared_ptr<HandleType>(new HandleType(_handle), _dx);
}
then:
auto closeHandleDeleter = [](HANDLE* h) {
::CloseHandle(*h);
delete h;
};
std::shared_ptr<HANDLE> sp = make_shared_handle(a_HANDLE, closeHandleDeleter);
f_that_takes_handle(*sp.get());
what I like most about this is there is no extra work to have access to this:
std::weak_ptr<HANDLE> wp = sp; // Yes. This could make sense in some designs.
and of course, the helper function works with any handle type of the likes.