Logo

Blog


unique_ptr and the pointer to implementation idiom

Last time, I wrote about unique_ptr and PImpl, demonstrating why you can't use a unique_ptr for PImpl. This time, I'd like to show you how you can make unique_ptr work with PImpl.

Remember, this is the code I initially presented back in When an empty destructor is required.

1
2
3
4
5
6
7
A Header file
class Apple {
  std::unique_ptr<class Orange> mOrange{};

public:
  ~Apple();
};

You saw in my last post Smart pointers and the pointer to implementation idiom that in contrast to the shared_ptr a unique_ptr doesn't do type erasure and hence eagerly tries to find the definition of the data pointer.

Providing a custom deleter function that you forward declare is one trick to how you can use a unqiue_ptr with PImpl. The following code illustrates this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
class Apple {
  std::unique_ptr<class Orange,
                  A using a custom deleter
                  decltype([](class Orange* ptr) {
                    B Forward declaring the real deleter function
                    void OrangeDeleter(class Orange*);

                    OrangeDeleter(ptr);
                  })>
    mOrange{};
};

void Test()
{
  C Some use without knowing the type Orange
  Apple a{};
}

I'm using C++20 for the solution because, that way, my code is shorter. InA, I provide a custom deleter. Thanks to C++20, I can use a capture-less lambda inside a decltype expression. The lambda takes an Orange pointer as a parameter. In the lambda's body, I forward declare the real deleter function B OrangeDeleter and call the function in the new line. All I have to do is provide OrangeDeleter in the implementation file of Apple, and I can completely hide Orange.

Book an in-house C++ training class

Do you like this content?

I'm available for in-house C++ training classes worldwide, on-site or remote. Here is a sample list of my classes:
  • From C to C++
  • Programming with C++11 to C++17
  • Programming with C++20
All classes can be customized to your team's needs. Training services

If you wonder about the lambda I'm using, please refer to this post for more context: Understanding the inner workings of C++ smart pointers - The unique_ptr with custom deleter or the YouTube episode C++ Insights - Episode 34: C++20: Captureless lambdas in unevaluated contexts. You can also find more about C++20s enhancements to lambda in my book Programming with C++20 - Concepts, Coroutines, Ranges, and more.

Andreas