使用 C++11+ 的 Libevent unique_ptr

Libevent with C++11+ unique_ptr

我最近尝试用 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 结构编写 RAII 包装器?

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

由于 std::unique_ptr 没有 type-erase 它的删除器,并且 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>;

header event2/event.h 故意不定义 event_base 以便实现是私有的。

CPP Reference 说:

std::unique_ptr may be constructed for an incomplete type T, such as to facilitate the use as a handle in the pImpl idiom. If the default deleter is used, T must be complete at the point in code where the deleter is invoked, which happens in the destructor, move assignment operator, and reset member function of std::unique_ptr.

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

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