unique_ptr、自定义删除程序和零法则

unique_ptr, custom deleter, and Rule of Zero

本文关键字:删除程序 自定义 ptr unique      更新时间:2023-10-16

我正在编写一个使用使用 C 接口创建的两个对象的类。对象如下所示:

typedef struct... foo_t;
foo_t* create_foo(int, double, whatever );
void delete_foo(foo_t* );

(同样适用于bar_t)。因为 C++11,我想将它们包装在一个智能指针中,这样我就不必编写任何特殊方法。该类将拥有两个对象的唯一所有权,因此unique_ptr逻辑上是有意义的......但我仍然必须编写一个构造函数:

template <typename T>
using unique_ptr_deleter = std::unique_ptr<T, void(*)(T*)>;
struct MyClass {
     unique_ptr_deleter<foo_t> foo_;
     unique_ptr_deleter<bar_t> bar_;
     MyClass()
         : foo_{nullptr, delete_foo}
         , bar_{nullptr, delete_bar}
     { }
     ~MyClass() = default;
     void create(int x, double y, whatever z) {
         foo_.reset(create_foo(x, y, z));
         bar_.reset(create_bar(x, y, z));
};

另一方面,使用 shared_ptr ,我不必编写构造函数或使用类型别名,因为我可以将delete_foo传入 reset() - 尽管这将使我的MyClass可复制,我不希望这样。

使用unique_ptr语义编写MyClass并仍然遵守零规则的正确方法是什么?

你的类不需要声明析构函数(无论你是否声明它为默认值,它都会得到正确的默认实现),所以仍然遵守"零规则"。

但是,您可以通过使删除器函数对象而不是指针来改善这一点:

template <typename T> struct deleter;
template <> struct deleter<foo_t> {
    void operator()(foo_t * foo){delete_foo(foo);}
};
template <> struct deleter<bar_t> {
    void operator()(bar_t * bar){delete_bar(bar);}
};
template <typename T>
using unique_ptr_deleter = std::unique_ptr<T, deleter<T>>;

这有几个好处:

  • unique_ptr不需要存储额外的指针
  • 删除函数可以直接调用,而不是通过指针调用
  • 你不需要编写构造函数;默认构造函数将做正确的事情。