根据下表,当您将 aunique_ptr<T>
用于前向声明的类型T
时,unique_ptr
析构函数需要T
是完整的,但移动赋值运算符(和reset
)也需要:
https://stackoverflow.com/a/6089065/1794803
因此,对于您的pImpl
习惯用法,要正确实现它,您必须声明delete
and 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);
};
但是,既然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.
};
这不是更好的解决方案吗?(+ 定义或删除您自己的复制/移动运算符,如果您想分类是否可复制/可移动;但这是一个“有意识的选择”;但是,不写移动分配unique_ptr
是错误的)。
使用 a unique_ptr
only 可以节省您在析构函数中编写 a delete p_impl
,无论如何您都必须声明。
unique_ptr
对于即使在异常情况下也会被破坏的局部动态对象是一个很好的选择,但是对于“属性”,如果你不记得你必须重写移动赋值运算符,你除了获得 UB 的可能性之外什么也没有保存。