← Patterns

The PIMPL idiom

12345678910111213141516171819202122232425262728293031323334353637383940414243// foo.h - header file #include <memory> class foo { public: foo(); ~foo(); foo(foo&&); foo& operator=(foo&&); private: class impl; std::unique_ptr<impl> pimpl; }; // foo.cpp - implementation file class foo::impl { public: void do_internal_work() { internal_data = 5; } private: int internal_data = 0; }; foo::foo() : pimpl{std::make_unique<impl>()} { pimpl->do_internal_work(); } foo::~foo() = default; foo::foo(foo&&) = default; foo& foo::operator=(foo&&) = default;

This pattern is licensed under the CC0 Public Domain Dedication.

Requires c++11 or newer.

Intent

Remove compilation dependencies on internal class implementations and improve compile times.

Description

When a header file changes, any files that #include that file will need to be recompiled. In the case of a class header, this is true even if those changes only apply to private members of the class. The PIMPL idiom hides private members from any users of the header file, allowing these internal details to change without requiring recompilation of the client code.

Lines 5–17 define a class, foo, to which we have applied the PIMPL idiom. This class definition includes only the public interface of the class and a pointer to the internal implementation. We use a std::unique_ptr (line 16) to ensure the lifetime of the implementation is managed correctly, which we initialise in foos constructor (line 35).

While the internal implementation class, impl, is declared in the header file on line 15, its definition appears in the implementation file on lines 22–32. This allows the class definition to change without requiring users of foo to recompile.

We have explicitly defaulted foo’s destructor on line 40, which is necessary because the destructor needs to be able to see the complete definition of impl (in order to destroy the std::unique_ptr). Note that we have also explicitly defaulted the move constructor and assignment operator on lines 42–43 so that foo can be moved. To make foo copyable, we must also implement the copy constructor and assignment operator.

Note: std::make_unique was introduced in C++14. For C++11, you can roll your own implementation.

Contributors

  • Joseph Mansfield
  • Mehdi Amini

Last Updated

09 December 2017

Source

Fork this pattern on GitHub

Share