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

Per*_*-lk 3 c++ raii unique-ptr raw-pointer

当您将 a 用于unique_ptr<T>前向声明的类型时Tunique_ptr析构函数要求 theT是完整的,但还需要移动赋值运算符(和reset),根据此表:

/sf/answers/426234581/

因此,对于您的pImpl习惯用法,要正确实现它,您必须声明 thedelete和 the move 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);
};
Run Code Online (Sandbox Code Playgroud)

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

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.
};
Run Code Online (Sandbox Code Playgroud)

这不是更好的解决方案吗?(如果您想要类可复制/可移动,则定义或删除您自己的复制/移动运算符;但这是一个“有意识的选择”;但是,不要为其编写移动赋值unique_ptr是一个错误)。

使用 a only 可以节省您在无论如何都必须声明的析构函数中unique_ptr编写 a 的麻烦。delete p_impl

unique_ptr对于本地动态对象来说,这是一个很好的选择,即使在出现异常的情况下,它也会被破坏,但是对于“属性”来说,如果您不记得必须重写移动赋值运算符,除了获得 UB 的可能性之外,您什么也没有保存。

πάν*_*ῥεῖ 5

好吧,使用 a可以让您免于为的std::unique_ptr显式操作而烦恼。deletep_impl

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