2

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.

Community
  • 1
  • 1
Peregring-lk
  • 9,237
  • 6
  • 37
  • 86

2 Answers2

4

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).

πάντα ῥεῖ
  • 83,259
  • 13
  • 96
  • 175
  • Moreover, an `std::unique_ptr` without a custom deleter is comparable to a raw pointer in terms of size, once optimized. – skypjack Dec 10 '16 at 18:14
0

std::unique_ptr should be the preferred way for pimpl according. For reference, see Herb Sutter's talk at CppCon16 at around 10mins. The reason is, it will prevent you from accidently changing your pimpl while maintining RAII.

pokey909
  • 1,717
  • 1
  • 15
  • 21