带有 C++11+ unique_ptr 的 Libevent

Posted

技术标签:

【中文标题】带有 C++11+ unique_ptr 的 Libevent【英文标题】:Libevent with C++11+ unique_ptr 【发布时间】: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 中前向声明的。所以没有选项来包装它?

【问题讨论】:

【参考方案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

【讨论】:

以上是关于带有 C++11+ unique_ptr 的 Libevent的主要内容,如果未能解决你的问题,请参考以下文章

C++11 unique_ptr智能指针详解

C++11之 unique_ptr

在 c++11 模式下使用带有仅移动参数的 QtConcurrent::run

[C++11]独占的智能指针unique_ptr的初始化和使用

[C++11]独占的智能指针unique_ptr的删除器

使用 C++11 for() 循环遍历 vector<unique_ptr<mytype>>