gpt4 book ai didi

c++ - 非指针上的 RAII 单线?

转载 作者:IT老高 更新时间:2023-10-28 21:43:51 29 4
gpt4 key购买 nike

相关主题

std::unique_ptr, deleters and the Win32 API

要将 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));

最佳答案

众所周知,使用 std::unique_ptr RAII FILE* 的示例:

struct FILEDeleter
{
typedef FILE *pointer;
void operator()(FILE *fp) { fclose(fp); }
};

typedef std::unique_ptr<FILE, FILEDeleter> FilePtr;

FilePtr f(fopen("file.txt", "r"));

唉,POSIX close() 到 RAII 文件描述符的类似方法是不可能的:

struct FDDeleter
{
typedef int pointer;
void operator()(int fd) { close(fp); }
};

typedef std::unique_ptr<int, FDDeleter> FD;

虽然有些编译器可以正常工作,但它是无效的,因为 fd==0 是一个有效的文件描述符!空值应该是 -1。但是不管怎样,即使是0还是无效的,因为FDDeleter::pointer要满足NullablePointer的要求(总结) :

  1. 应与 nullptr 相当。
  2. 它应该被初始化为一个比较等于nullptr的值。

于是,UniqueHandle就诞生了!

#include <memory>

template <typename T, T TNul = T()>
class UniqueHandle
{
public:
UniqueHandle(std::nullptr_t = nullptr)
:m_id(TNul)
{ }
UniqueHandle(T x)
:m_id(x)
{ }
explicit operator bool() const { return m_id != TNul; }

operator T&() { return m_id; }
operator T() const { return m_id; }

T *operator&() { return &m_id; }
const T *operator&() const { return &m_id; }

friend bool operator == (UniqueHandle a, UniqueHandle b) { return a.m_id == b.m_id; }
friend bool operator != (UniqueHandle a, UniqueHandle b) { return a.m_id != b.m_id; }
friend bool operator == (UniqueHandle a, std::nullptr_t) { return a.m_id == TNul; }
friend bool operator != (UniqueHandle a, std::nullptr_t) { return a.m_id != TNul; }
friend bool operator == (std::nullptr_t, UniqueHandle b) { return TNul == b.m_id; }
friend bool operator != (std::nullptr_t, UniqueHandle b) { return TNul != b.m_id; }

private:
T m_id;
};

它的使用很简单,最好看一个例子:

struct FDDeleter
{
typedef UniqueHandle<int, -1> pointer;
void operator()(pointer p)
{
close(p);
}
};
typedef std::unique_ptr<int, FDDeleter> FD;

FD fd(open("test.txt", O_RDONLY));

如果你真的想要一个单线,你可以用这个概括:

template <typename T, T TNul = T(), typename RD, RD (*D)(T)>
struct OLDeleter
{
typedef UniqueHandle<T, TNul> pointer;
void operator()(pointer p)
{
D(p);
}
};

然后只有一行:

std::unique_ptr<int, OLDeleter<int, -1, int, close> > FD fd(open("test.txt", O_RDONLY));

问题是您必须将 close() 的返回值添加为模板参数,并假设该函数没有任何有趣的地方可以防止其转换​​为 int( *)(int)(奇怪的调用约定,额外的参数,宏...),这很不方便。

你可以添加一个函数包装器:

void my_close(int fd) { close(fd); }

但如果你喜欢它,你也可以编写整个struct FDDeleter

关于c++ - 非指针上的 RAII 单线?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24611215/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com