In VC2012, I want to create a mutex in a constructor using a unique pointer and a deleter, so that I don\'t need to create a destructor just to call CloseHandle.
I w
The problem is you actually define unque_ptr that holds pointer to handle (HANDLE*) type, but you pass just HANDLE, not pointer to it.
Forget about the custom deleter for now. When you say std::unique_ptr<T>
, the unique_ptr
constructor expects to receive a T*
, but CreateMutex
returns a HANDLE
, not a HANDLE *
.
There are 3 ways to fix this:
std::unique_ptr<void, deleter> m_mutex;
You'll have to cast the return value of CreateMutex
to a void *
.
Another way to do this is use std::remove_pointer to get to the HANDLE
's underlying type.
std::unique_ptr<std::remove_pointer<HANDLE>::type, deleter> m_mutex;
Yet another way to do this is to exploit the fact that if the unique_ptr
's deleter contains a nested type named pointer
, then the unique_ptr
will use that type for its managed object pointer instead of T*
.
struct mutex_deleter {
void operator()( HANDLE h )
{
::CloseHandle( h );
}
typedef HANDLE pointer;
};
std::unique_ptr<HANDLE, mutex_deleter> m_mutex;
foo() : m_mutex(::CreateMutex(NULL, FALSE, NULL), mutex_deleter()) {}
Now, if you want to pass a pointer to function type as the deleter, then when dealing with the Windows API you also need to pay attention to the calling convention when creating function pointers.
So, a function pointer to CloseHandle must look like this
BOOL(WINAPI *)(HANDLE)
Combining all of it,
std::unique_ptr<std::remove_pointer<HANDLE>::type,
BOOL(WINAPI *)(HANDLE)> m_mutex(::CreateMutex(NULL, FALSE, NULL),
&::CloseHandle);
I find it easier to use a lambda instead
std::unique_ptr<std::remove_pointer<HANDLE>::type,
void(*)( HANDLE )> m_mutex;
foo() : m_mutex(::CreateMutex(NULL, FALSE, NULL),
[]( HANDLE h ) { ::CloseHandle( h ); }) {}
Or as suggested by @hjmd in the comments, use decltype
to deduce the type of the function pointer.
std::unique_ptr<std::remove_pointer<HANDLE>::type,
decltype(&::CloseHandle)> m_mutex(::CreateMutex(NULL, FALSE, NULL),
&::CloseHandle);
Others have pointed out how the whole HANDLE
/HANDLE*
issue works. Here's a much cleverer way to deal with it, using interesting features of std::unique_pointer
.
struct WndHandleDeleter
{
typedef HANDLE pointer;
void operator()(HANDLE h) {::CloseHandle(h);}
};
typedef std::unique_ptr<HANDLE, WndHandleDeleter> unique_handle;
This allows unique_handle::get
to return HANDLE
instead of HANDLE*
, without any fancy std::remove_pointer
or other such things.
This works because HANDLE
is a pointer and therefore satisfies NullablePointer.