C++/pimpl:原始指针还是 unique_ptr?什么是更好的选择?

C++/pimpl: raw pointer or unique_ptr? What is a better choice?

当您对前向声明类型 T 使用 unique_ptr<T> 时,unique_ptr 析构函数要求 T 完成,但移动赋值运算符也是如此(和 reset),根据这个 table:

因此,对于您的 pImpl 习语,要正确实现它,您必须声明 deletemove assignment method(作为副作用,将它们标记为非内联):

class impl_t;

class A
{
   std::unique_ptr<impl_t> p_impl;

public:
   // Implement in A.cpp as A::~A() = default;
   ~A();

   // Implemented in A.cpp as A& operator=(A&&) = default;
   A& operator=(A&& he);
};

但是,由于 std::unique_ptr 是动态内存的 RAII 解决方案,而您 pImpl 已经在 class 中,并且无论如何您都被迫编写析构函数,是不是最好只管理一个原始指针,因为从 p_impl 的角度来看,你 class 已经是一个类 RAII?:

class impl_t;

class A
{
    impl_t* p_impl;

public:
    ~A(); // The destructor must be written anyway.

    // The omitted move assignment destructor doesn't cause UB.
};

这不是更好的解决方案吗? (如果你想 class 是否为 copyable/movable,则 + 定义或删除你自己的 copy/move 运算符;但那是一个 "conscious choice";但是,不要编写移动赋值因为 unique_ptr 是一个错误)。

使用 unique_ptr 只会节省您在必须声明的析构函数中编写 delete p_impl 的时间。

unique_ptr 是局部动态对象的绝佳选择,即使在发生异常的情况下也会被破坏,但是对于 "attributes",除了如果不这样做可能会获得 UB 之外,什么都没有保存记住你必须重写移动赋值运算符。

好吧,使用 std::unique_ptr 可以让您免于为 p_impl.

显式 delete 而烦恼

此外,在并发访问的情况下和构造函数中的异常情况下它应该也能很好地工作(这似乎不能保证使用原始指针和 new 你自己)。

std::unique_ptr 应该是 pimpl 的首选方式。作为参考,请参阅 10 分钟左右的 Herb Sutter's talk at CppCon16。 原因是,它可以防止您在维护 RAII 时意外更改您的 pimpl。