当你使用一个前置声明类型
这是不是更好的解决方案?(+如果你想将类标记为可复制/可移动,请定义或删除自己的复制/移动运算符;但这是一个“明智的选择”;然而,为
仅使用
T
的unique_ptr<T>
时,unique_ptr
析构函数需要T
是完整的,但是移动赋值运算符(和reset
)也是如此,根据这个表格:https://dev59.com/bm025IYBdhLWcg3wbVan#6089065
所以,对于你的pImpl
惯用法,为了正确实现它,你必须声明delete
和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
已经在一个类中,您无论如何都必须编写一个析构函数,那么管理原始指针是否更好呢?因为从p_impl
的角度来看,您的类已经类似于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.
};
这是不是更好的解决方案?(+如果你想将类标记为可复制/可移动,请定义或删除自己的复制/移动运算符;但这是一个“明智的选择”;然而,为
unique_ptr
编写移动赋值是一个错误)。仅使用
unique_ptr
只能使您在析构函数中写入delete p_impl
,而您必须在任何情况下都要声明析构函数。
unique_ptr
是局部动态对象的理想选择,即使出现异常也会被销毁,但对于“属性”,除了可能忘记重写移动赋值运算符并得到UB之外,没有任何节省。
std::unique_ptr
在优化后的大小方面与原始指针相当。 - skypjack