std::unique_ptr, deleters and the Win32 API
c++, c++11, unique-ptr, winapi
Solution
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);
Problem
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 would have thought that this would work: ``` struct foo { std::unique_ptr<HANDLE, BOOL(*)(HANDLE)> m_mutex; foo() : m_mutex(CreateMutex(NULL, FALSE, NULL), CloseHandle) {} } ``` but on compiling I get an error: ``` error C2664: 'std::unique_ptr<_Ty,_Dx>::unique_ptr(void *,int (__cdecl *const &)(HANDLE)) throw()' : cannot convert parameter 1 from 'HANDLE' to 'void *' ``` When I modify the constructor thus: ``` foo() : m_mutex((void*)CreateMutex(NULL, FALSE, (name + " buffer mutex").c_str()), CloseHandle) {} ``` I get the even more unusual: ``` error C2664: 'std::unique_ptr<_Ty,_Dx>::unique_ptr(void *, int (__cdecl *const &)(HANDLE)) throw()' : cannot convert parameter 1 from 'void *' to 'void *' ``` I'm at a loss now. HANDLE is a typedef for void*: is there some conversion magic I need to know about?