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?
Forget about the custom deleter for now. When you say
std::unique_ptr<T>, theunique_ptrconstructor expects to receive aT*, butCreateMutexreturns aHANDLE, not aHANDLE *.There are 3 ways to fix this:
You’ll have to cast the return value of
CreateMutexto avoid *.Another way to do this is use
std::remove_pointerto get to theHANDLE‘s underlying type.Yet another way to do this is to exploit the fact that if the
unique_ptr‘s deleter contains a nested type namedpointer, then theunique_ptrwill use that type for its managed object pointer instead ofT*.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
CloseHandlemust look like thisCombining all of it,
I find it easier to use a lambda instead
Or as suggested by @hjmd in the comments, use
decltypeto deduce the type of the function pointer.