非指针上的RAII单线程?

 ZZDXP 发布于 2023-01-06 07:24

相关主题

std :: unique_ptr,deleters和Win32 API

要将Win32句柄用作RAII,我可以使用以下行

std::unique_ptr::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 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 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
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, ::closesocket>> sock2(socket(AF_UNSPEC, SOCK_STREAM, IPPROTO_UDP));

rodrigo.. 10

众所周知,RAII FILE*使用的例子std::unique_ptr如下:

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

typedef std::unique_ptr 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 FD;

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

    它应该是可比的nullptr.

    它应该被初始化为一个比较等于的值nullptr.

因此,UniqueHandle诞生了!

#include 

template 
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 pointer;
    void operator()(pointer p)
    {
        close(p);
    }
};
typedef std::unique_ptr FD;

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

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

template 
struct OLDeleter
{
    typedef UniqueHandle pointer;
    void operator()(pointer p)
    {
        D(p);
    }
};

然后只有一行:

std::unique_ptr > FD fd(open("test.txt", O_RDONLY));

问题是你必须添加close()作为模板参数的返回,并假设没有任何有趣的关于这个函数阻止它转换为int(*)(int)(奇怪的调用约定,额外的参数,宏......),这是非常不方便的.

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

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

但如果你进入它,你也可以写出整体struct FDDeleter.

撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有