在 VC2012 中,我想在构造函数中使用唯一指针和删除器创建互斥锁,这样我就不需要创建析构函数来调用 CloseHandle。
我原以为这会起作用:
struct foo
{
std::unique_ptr<HANDLE, BOOL(*)(HANDLE)> m_mutex;
foo() : m_mutex(CreateMutex(NULL, FALSE, NULL), CloseHandle) {}
}
但在编译时出现错误:
error C2664: 'std::unique_ptr<_Ty,_Dx>::unique_ptr(void *,int
(__cdecl *const &)(HANDLE)) throw()' : cannot convert parameter 1 from
'HANDLE' to 'void *'
当我这样修改构造函数时:
foo() : m_mutex((void*)CreateMutex(NULL, FALSE,
(name + " buffer mutex").c_str()), CloseHandle) {}
我得到了更不寻常的:
error C2664: 'std::unique_ptr<_Ty,_Dx>::unique_ptr(void *,
int (__cdecl *const &)(HANDLE)) throw()' : cannot convert
parameter 1 from 'void *' to 'void *'
我现在很茫然。 HANDLE 是 void* 的 typedef:我需要了解一些转换魔法吗?
最佳答案
暂时忘记自定义删除器。当你说 std::unique_ptr<T>
, unique_ptr
构造函数期望收到 T*
, 但是 CreateMutex
返回 HANDLE
,而不是 HANDLE *
.
有 3 种方法可以解决此问题:
std::unique_ptr<void, deleter> m_mutex;
您必须转换 CreateMutex
的返回值到 void *
.
另一种方法是使用 std::remove_pointer
前往HANDLE
的基础类型。
std::unique_ptr<std::remove_pointer<HANDLE>::type, deleter> m_mutex;
另一种方法是利用以下事实:如果 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()) {}
现在,如果你想传递一个指向函数类型的指针作为删除器,那么在处理Windows API时你还需要注意创建函数指针时的调用约定。
所以,一个指向 CloseHandle
的函数指针一定是这样的
BOOL(WINAPI *)(HANDLE)
结合所有这些,
std::unique_ptr<std::remove_pointer<HANDLE>::type,
BOOL(WINAPI *)(HANDLE)> m_mutex(::CreateMutex(NULL, FALSE, NULL),
&::CloseHandle);
我发现改用 lambda 会更容易
std::unique_ptr<std::remove_pointer<HANDLE>::type,
void(*)( HANDLE )> m_mutex;
foo() : m_mutex(::CreateMutex(NULL, FALSE, NULL),
[]( HANDLE h ) { ::CloseHandle( h ); }) {}
或者按照@hjmd 在评论中的建议,使用decltype
推断函数指针的类型。
std::unique_ptr<std::remove_pointer<HANDLE>::type,
decltype(&::CloseHandle)> m_mutex(::CreateMutex(NULL, FALSE, NULL),
&::CloseHandle);
关于c++ - std::unique_ptr、删除器和 Win32 API,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14841396/