c++ - std::unique_ptr、删除器和 Win32 API

标签 c++ winapi c++11 unique-ptr

在 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/

相关文章:

c++ - boost::any 类型更改导致非法访问

c++ - 如何从 .t​​xt 文件中获取初始化的指针

c++ - Qt5 在多宿主网络上绑定(bind) TCP 套接字

windows - Windows 7 shell 中未完全显示可执行版本

c++ - 主线程是否在阻塞线程上运行?

c++ - 在 C++ 中,如何从声明中获取任意函数的类型?

c++ - 用复利计算总返回

windows - 为什么 Unicode Windows 标题栏(仅)是问号(?)代码点?

winapi - 记录USB鼠标事件

c++ - 多任务处理在我的 C++11 程序中不起作用