c++ - 类数据成员 ABI 的 std::unique_ptr(Pimpl 习惯用法)

标签 c++ c++11 unique-ptr abi pimpl-idiom

我正在尝试定义现有代码,这些代码使用要用 unique_ptr 定义的“pimpl”数据成员。有些对象需要自定义删除器,有些则不需要。

unique_ptr(与 shared_ptr 不同)析构函数需要知道对象的完整类型。所以需要在数据成员声明中指定删除器:

class Foo {
public:
   ...
   ~Foo (void) //in source file  =default
private:
   class FooImpl;
   std::unique_ptr <FooImpl> _pimpl;
};

在实例化 pimpl 时,您只能使用默认删除器。如果你想要一个自定义的删除器,你需要在声明中指定它

class Foo {
public:
   ...
   ~Foo (void) //in source file  =default
private:
   class FooImpl;
   std::unique_ptr <FooImpl,  std::function <void (FooImpl*&)> > _pimpl;
};

但是,无论您是想要具有默认行为的 unique_ptr d'tor 还是自定义删除器,您都无法灵活选择。更灵活的选项是第二个版本,但如果您选择保持默认行为,则必须使用等同于默认删除的特定删除器实例化 unique_ptr,例如:

Foo::Foo (void) :
    _impl (new CurveItemWidgetImpl, std::default_delete <FooImpl> ()) {
}

那么,std::unique_ptr 是处理 ABI 的最佳方式吗(与 shared_ptr 或原始指针相比)?

最佳答案

您可以轻松提供有效调用不透明符号的删除器:

class Foo {
public:
  ~Foo(); // = default
private:
  class FooImpl;
  struct FooImplDelete { void operator()(FooImpl*); };
  std::unique_ptr<FooImpl, FooImplDelete> _pimpl;
};

现在您可以将 Foo::FooImplDelete::operator() 的定义移动到您的源文件中。实际上,优化编译器会将其内联到 Foo 的析构函数中。

如果您没有特别的理由怀疑需要自定义删除器,您也可以使用默认的;如果您需要将自定义删除器更改为 release unique_ptr:

Foo::Foo() try
  : _pimpl(new FooImpl)
{
}
catch(...)
{
  delete _pimpl.release();
}

Foo::~Foo()
{
  delete _pimpl.release();
}

关于c++ - 类数据成员 ABI 的 std::unique_ptr(Pimpl 习惯用法),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30072094/

相关文章:

c++ - g++ 模板名称修改

c++ - 可变参数模板和混入的歧义错误

c++ - 无法将 unique_ptr 添加到 std::array

c++ - 将 for_each 与 std::unique_ptr 一起使用

c++ - 模板转换运算符

c++11 - 右值引用返回如何工作?

c++ - C++调用回调后删除一个对象

c++ - 可变参数模板类中的定义数量不同

c++ - 构造函数依赖注入(inject) : unique_ptr + move vs shared_ptr

c++ - 使用 Qt 检查字符串是否是有效的文件名