hat*_*cat 26 c++ winapi unique-ptr c++11
在VC2012中,我想使用唯一指针和删除器在构造函数中创建一个互斥锁,这样我就不需要创建一个析构函数来调用CloseHandle.
我原以为这会起作用:
struct foo
{
std::unique_ptr<HANDLE, BOOL(*)(HANDLE)> m_mutex;
foo() : m_mutex(CreateMutex(NULL, FALSE, NULL), CloseHandle) {}
}
Run Code Online (Sandbox Code Playgroud)
但在编译时我收到一个错误:
error C2664: 'std::unique_ptr<_Ty,_Dx>::unique_ptr(void *,int
(__cdecl *const &)(HANDLE)) throw()' : cannot convert parameter 1 from
'HANDLE' to 'void *'
Run Code Online (Sandbox Code Playgroud)
当我修改构造函数时:
foo() : m_mutex((void*)CreateMutex(NULL, FALSE,
(name + " buffer mutex").c_str()), CloseHandle) {}
Run Code Online (Sandbox Code Playgroud)
我变得更加不寻常:
error C2664: 'std::unique_ptr<_Ty,_Dx>::unique_ptr(void *,
int (__cdecl *const &)(HANDLE)) throw()' : cannot convert
parameter 1 from 'void *' to 'void *'
Run Code Online (Sandbox Code Playgroud)
我现在不知所措.HANDLE是void*的typedef:我需要了解一些转换魔法吗?
Pra*_*ian 47
暂时忘掉自定义删除器.当你说std::unique_ptr<T>,unique_ptr构造函数期望接收a T*,但CreateMutex返回a HANDLE,而不是a HANDLE *.
有3种方法可以解决这个问题:
std::unique_ptr<void, deleter> m_mutex;
Run Code Online (Sandbox Code Playgroud)
你必须将返回值转换CreateMutex为a void *.
另一种方法是使用std::remove_pointer到达HANDLE底层类型.
std::unique_ptr<std::remove_pointer<HANDLE>::type, deleter> m_mutex;
Run Code Online (Sandbox Code Playgroud)
另一种方法是利用如下事实:如果unique_ptr删除器包含一个名为的嵌套类型pointer,那么unique_ptr将使用该类型作为其托管对象指针而不是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()) {}
Run Code Online (Sandbox Code Playgroud)
现在,如果要将指向函数类型的指针作为删除器传递,那么在处理Windows API时,还需要在创建函数指针时注意调用约定.
所以,一个函数指针CloseHandle必须看起来像这样
BOOL(WINAPI *)(HANDLE)
Run Code Online (Sandbox Code Playgroud)
结合所有这些,
std::unique_ptr<std::remove_pointer<HANDLE>::type,
BOOL(WINAPI *)(HANDLE)> m_mutex(::CreateMutex(NULL, FALSE, NULL),
&::CloseHandle);
Run Code Online (Sandbox Code Playgroud)
我发现使用lambda更容易
std::unique_ptr<std::remove_pointer<HANDLE>::type,
void(*)( HANDLE )> m_mutex;
foo() : m_mutex(::CreateMutex(NULL, FALSE, NULL),
[]( HANDLE h ) { ::CloseHandle( h ); }) {}
Run Code Online (Sandbox Code Playgroud)
或者如@hjmd在评论中所建议的那样,decltype用来推断函数指针的类型.
std::unique_ptr<std::remove_pointer<HANDLE>::type,
decltype(&::CloseHandle)> m_mutex(::CreateMutex(NULL, FALSE, NULL),
&::CloseHandle);
Run Code Online (Sandbox Code Playgroud)
Nic*_*las 31
其他人指出整个HANDLE/ HANDLE*问题是如何运作的.使用有趣的功能,这是一个更聪明的方式来处理它std::unique_pointer.
struct WndHandleDeleter
{
typedef HANDLE pointer;
void operator()(HANDLE h) {::CloseHandle(h);}
};
typedef std::unique_ptr<HANDLE, WndHandleDeleter> unique_handle;
Run Code Online (Sandbox Code Playgroud)
这允许unique_handle::get返回HANDLE而不是HANDLE*没有任何花哨std::remove_pointer或其他这样的东西.
这是因为HANDLE是一个指针,因此满足NullablePointer.