Связанная тема
std:: unique_ptr, удалители и API Win32
Чтобы использовать ручку Win32 как RAII, я могу использовать следующую строку
std::unique_ptr<std::remove_pointer<HANDLE>::type, decltype(&CloseHandle)> m_mutex(CreateMutex(NULL, FALSE, NULL), &::CloseHandle);
Для меня это чистый однострочный лайнер и делает именно то, что я хочу.
Когда дело доходит до SOCKET, он не будет компилироваться с этой же строкой, так как SOCKET не может быть nullptr.
Что мне нужно сделать, чтобы заставить его работать, это следующее:
struct SocketDeleter
{
typedef SOCKET pointer;
void operator()(SOCKET h)
{
::closesocket(h);
}
};
// Start listen socket.
std::unique_ptr<SOCKET, SocketDeleter> sock(socket(AF_UNSPEC, SOCK_STREAM, IPPROTO_UDP));
Что мне не нравится в этой реализации, так это то, что любой другой тип ресурсов, которые я хочу использовать, мне нужно будет скопировать/вставить тот же код, чтобы только изменить функцию закрытия.
Я мог бы использовать макрос, но это действительно уродливо и не может использоваться дважды
#define RAII_UNIQUE_RESOURCE(varName, classType, init, closure) \
struct deleterMacro \
{ \
typedef classType pointer; \
void operator()(classType h) \
{ \
closure(h); \
} \
}; \
std::unique_ptr<classType, deleterMacro> varName(init);
// Compile, but breaks as soon as 2 sockets defined.
RAII_UNIQUE_RESOURCE(sock, SOCKET, socket(AF_UNSPEC, SOCK_STREAM, IPPROTO_UDP), ::closesocket);
Я попытался использовать шаблон, но я не могу передать свой указатель на функцию operator(), насколько мне известно.
template<class T, class methodDeclaration, class pFuncPointer>
struct deleter
{
typedef T pointer;
void operator()(T h)
{
// Is there a way??
methodDeclaration toCall = pFuncPointer;
toCall(h);
}
};
// With a call such as ...
std::unique_ptr<SOCKET, deleter<SOCKET, std::function<decltype(::closesocket)>, ::closesocket>> sock2(socket(AF_UNSPEC, SOCK_STREAM, IPPROTO_UDP));