【问题标题】:Generic handle class通用句柄类
【发布时间】:2016-10-20 19:34:26
【问题描述】:

我偶然发现了这个问题:Using unique_ptr to control a file descriptorstd::unique_ptr 并不适合通用句柄。更一般的类也是如此

template<class HandleType,HandleType nullvalue,class Deleter>
class Handle;

已经实现(也许在 boost 中),或者我应该自己动手。这个问题之前在 What wrapper class in C++ should I use for automated resource management?,但是现在我们有了 C++14,所以可以有更多的选择。

我还发现了以下提议:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3677.html。所以别人也想过这个问题。

【问题讨论】:

  • 单独的“删除”类或函数过于复杂。只需将文件描述符包装在一个类中,其析构函数会关闭文件描述符。然后,使用任何你想要的智能指针:unique_ptr 或 shared_ptr。
  • @SamVarshavchik : .. 或者根本不使用 ptrs,只需移动构造函数。
  • 老实说,我仍然认为 jalf 的答案是最好的答案,即使在 C++14 的世界中也是如此。每个实现都需要在构造函数和析构函数中调用不同的函数,而且代码还不够复杂,不足以让一个可重用的类值得付出努力。
  • @CodeGray。为什么当时写了unique_ptr。毕竟,这是一个特殊情况:template&lt;class T,class Deleter&gt; class unique_ptr:Handle&lt;T*,nullptr,Deleter&gt; + operator* 在一般情况下没有意义。
  • 呃,unique_ptr 旨在管理指针的生命周期。在大多数情况下,您不需要专门化它。您只需让默认实现调用删除即可。要处理其他 [非常罕见的] 情况,您可以使用自定义删除器提供自己的专业化。我真的不知道这与特定资源的包装类有什么关系。泛型类实际上将有no code,您必须自己提供整个实现。有什么意义?

标签: c++ raii resource-management


【解决方案1】:

C++ 标准中还没有这样的类,所以我决定write my own

template<typename Policy>
class unique_handle
{
    typename Policy::handle_type h;

public:
    unique_handle(const unique_handle&) = delete;

    typename Policy::handle_type get() const
    {
        return h;
    }

    typename Policy::handle_type release()
    {
        typename Policy::handle_type temp = h;
        h = Policy::get_null();
        return temp;
    }

    explicit operator bool() const
    {
        return !Policy::is_null(h);
    }

    bool operator!() const
    {
        return !static_cast<bool>(*this);
    }

    void reset(typename Policy::handle_type new_handle)
    {
        typename Policy::handle_type old_handle = h;
        h = new_handle;
        if(!Policy::is_null(old_handle))
        {
            Policy::close(old_handle);
        }
    }

    void swap(unique_handle& other)
    {
        std::swap(this->h, other.h);
    }

    void reset()
    {
        reset(Policy::get_null());
    }

    ~unique_handle()
    {
        reset();
    }

    unique_handle& operator=(unique_handle other) noexcept
    {
        this->swap(other);
        return *this;
    }

    unique_handle(unique_handle&& other) noexcept
    {
        this->h = other.h;
        other.h = Policy::get_null();
    }

    unique_handle()
    {
        h = Policy::get_null();
    }

    unique_handle(typename Policy::handle_type handle)
    {
        h = handle;
    }
};

示例用法:

#include <wiertlo/unique_handle.hpp>
#include <iostream>
#include <cassert>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

struct file_descriptor_policy
{
    typedef int handle_type;
    static void close(handle_type handle)
    {
        ::close(handle);
    }

    static handle_type get_null()
    {
        return -1;
    }

    static bool is_null(handle_type handle)
    {
        return handle == -1;
    }
};

int main()
{
    typedef wiertlo::unique_handle<file_descriptor_policy> file_descriptor;
    file_descriptor null_fd; // null file descriptor
    assert(!null_fd);
    file_descriptor fd(open("/dev/null", O_WRONLY));
    assert(fd);
    write(fd.get(), "test", 4);
    file_descriptor other = std::move(fd);
    assert(!fd);
    assert(other);
}

【讨论】:

  • 您的Policy::get_null() 是天才,解决了我长期存在的问题。太棒了,谢谢。
  • 我喜欢这种方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-12
  • 1970-01-01
  • 1970-01-01
  • 2020-07-14
相关资源
最近更新 更多