Ответ 1
Забудьте об пользовательском удалении на данный момент. Когда вы говорите std::unique_ptr<T>
, конструктор unique_ptr
ожидает получить T*
, но CreateMutex
возвращает a HANDLE
, а не HANDLE *
.
Есть три способа исправить это:
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
deleter содержит вложенный тип с именем 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);
Мне легче использовать лямбда вместо
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);