When you use a unique_ptr<T>
for a forward declared type T
, the unique_ptr
destructor requires the T
is complete, but the move assignment operator as well (and reset
), according to this table:
https://stackoverflow.com/a/6089065/1794803
So, for your pImpl
idiom, to implement it correctly, you have to declare the delete
and the move assignment method
(which, as side effect, marks them non-inlined):
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);
};
But, since std::unique_ptr
is a RAII-solution for dynamic memory, and you pImpl
is already inside a class, and you are forced to write a destructor anyway, isn't it better to just manage a raw pointer, since you class is already a RAII-like from the point of view of 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.
};
Isn't that a better solution? (+ defined or delete your own copy/move operator if you want to class is copyable/movable or not; but that is a "conscious choice"; however, don't writting a move assignment for unique_ptr
is an error).
Using a unique_ptr
only saves you for written a delete p_impl
in a destructor that you have to declare anyway.
unique_ptr
is an excellent choice for local dynamic objects which will be destructed even in case of exceptions, but for "attributes", you save nothing but the possibility of getting UB if you don't remember you have to rewrite the move assignment operator.
Well, using a std::unique_ptr
redeems you from bothering with the explicit delete
for the p_impl
.
Also it should work well in cases of concurrent access and exceptional cases in the constructor (which doesn't seem to be guaranteed using a raw pointer and new
yourself).