std :: unique_ptr,deleters和Win32 API [英] std::unique_ptr, deleters and the Win32 API

查看:231
本文介绍了std :: unique_ptr,deleters和Win32 API的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在VC2012中,我想使用一个唯一的指针和一个删除器在一个构造函数中创建一个互斥,所以我不需要创建一个析构函数来调用CloseHandle。



我会认为这会工作:

  struct foo 
{
std: :unique_ptr< HANDLE,BOOL(*)(HANDLE)> m_mutex;
foo():m_mutex(CreateMutex(NULL,FALSE,NULL),CloseHandle){}
}

但是在编译时我得到一个错误:

 错误C2664:'std :: unique_ptr& _Dx> :: unique_ptr(void *,int 
(__cdecl * const&)(HANDLE))throw()':不能将参数1从
'HANDLE'转换为'void *'



当我修改构造函数时:

  foo():m_mutex(void *)CreateMutex(NULL,FALSE,
(name +buffer mutex)。c_str()),CloseHandle){}

我得到更不寻常的:

 code> error C2664:'std :: unique_ptr< _Ty,_Dx> :: unique_ptr(void *,
int(__cdecl * const&)(HANDLE))throw() $ b参数1从'void *'到'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 的删除程序包含名为指针的嵌套类型,则 unique_ptr 将使用该类型对于其管理对象指针,而不是 T *

  struct mutex_deleter { 
void operator()(HANDLE h)
{
:: CloseHandle(h);
}
typedef HANDLE指针;
};
std :: unique_ptr< HANDLE,mutex_deleter> m_mutex;
foo():m_mutex(:: CreateMutex(NULL,FALSE,NULL),mutex_deleter()){}


b $ b




现在,如果你想传递一个指向函数类型的指针作为删除器,那么当处理Windows API时,你还需要注意调用约定



因此,一个指向 CloseHandle 必须如下所示

  BOOL(WINAPI *)(HANDLE)

  std :: unique_ptr< std :: remove_pointer< HANDLE> :: type,
BOOL )(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);


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>, 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);

这篇关于std :: unique_ptr,deleters和Win32 API的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆