【问题标题】:Libevent with C++11+ unique_ptr带有 C++11+ unique_ptr 的 Libevent
【发布时间】:2017-02-01 11:34:14
【问题描述】:

我最近尝试使用 std::unique_ptr 和自定义删除器包装 libdbus 类型和 libevent 类型以简化代码,但这些库出现错误:

/opt/cross/armv7hl-meego-linux-gnueabi/include/c++/4.8.3/bits/unique_ptr.h:65:22: error: invalid application of 'sizeof' to incomplete type 'sockets::libev::event_base'
  static_assert(sizeof(_Tp)>0,
                      ^

代码很简单:

namespace sockets {
    // ... unix sockets stuff
    namespace libev {
        #include <event.h>
    } // libev
} // sockets

class A {
public:
    void run() {
        using namespace sockets;
        using namespace sockets::libev;
        using UniqueEventBase = std::unique_ptr<event_base>;
        // ...
    }   
};

那么在这个例子中我该如何为event_base struct 编写RAII-wrappers 呢?

附:我发现event_base 结构是在event2/event.h 中前向声明的。所以没有选项来包装它?

【问题讨论】:

    标签: c++ c++11 unique-ptr libevent


    【解决方案1】:

    由于std::unique_ptr 不会对删除器进行类型擦除,并且the default deleter 不适用于不完整的类型,因此您需要提供替代删除器作为类型签名的一部分:

    struct EventBaseDeleter {
      void operator()(event_base* ptr) const {
        sockets::libev::event_base_free(ptr);
      }
    };
    
    using UniqueEventBase = std::unique_ptr<event_base, EventBaseDeleter>;
    

    【讨论】:

      【解决方案2】:

      标头 event2/event.h 故意不定义 event_base 以便实现保持私有。

      CPP Reference 说:

      std::unique_ptr 可以为不完整的类型 T 构造,以便于在 pImpl 习语中用作句柄。如果使用默认删除器,则 T 必须在代码中调用删除器的位置完成,这发生在 std::unique_ptr 的析构函数、移动赋值运算符和重置成员函数中。

      因此,您需要通过提供自己的删除器作为模板的第二个参数来避免使用默认删除器。

      这很有意义,尤其是在这种情况下,您希望调用event_base_free 而不是尝试delete

      【讨论】:

        猜你喜欢
        • 2016-11-23
        • 1970-01-01
        • 2013-02-24
        • 1970-01-01
        • 1970-01-01
        • 2014-07-01
        • 1970-01-01
        • 2018-09-30
        • 2016-04-12
        相关资源
        最近更新 更多