PIMPL
What is PIMPL?
The PIMPL C++ idiom is typically used to reduced compile-time dependencies and construct C++ library interfaces with a stable ABI (application binary interface). This technique involves moving the implementation details of a class from it's object representation into a separate class accessed through an opaque pointer.
Below is a sample implementation of the PIMPL idiom in C++.
Header File
class VisibleClass { VisibleClass(); ~VisibleClass(); // ... private: class HiddenImpl; // things to hide unique_ptr<HiddenImpl> pimpl_; // opaque ptr };
Implementation File
class VisibleClass::HiddenImpl { // ... }; VisibleClass::VisibleClass() : pimpl_(new HiddenImpl) {} VisibleClass::~VisibleClass() = default;
In C++, deleting a pointer in which its type is not defined (only forward declared) will lead to undefined behaviour. To prevent this,
unique_ptr
will check if the definition of the type its pointer to is visible before calling delete in its destructor. If we were to not declare the destructor of VisibleClass
, the compiler would generate an inlined version of it for us in the header file. Since the type of HiddenImpl
is incomplete in the header file, your code will not compile. The solution is to define your own destructor so that by the time unique_ptr
tries to deallocate the resources for HiddenImpl
in Line 6 of the implementation file, class VisibleClass::HiddenImpl;
will be fully defined.It is recommended that you place all private nonvirtual members into the
HiddenImpl
class. In doing so, you eliminate the need to pass a back pointer to access members in the VisibleClass
from HiddenImpl
. Unfortunately you cannot hide virtual members in the member functions of HiddenImpl
.When to use?
There are several reasons why you might want to use PIMPL in your code:
- Decrease Compilation times
Whenever the header file of class
X
changes, every client that usesX
has to be recompiled. With PIMPL, only the implementation ofX
has to be recompiled when you makes changes to the underlying fields/methods.
- Binary Compatibility
Adding new fields/methods to
HiddenImpl
will not affect the binary interface your end user sees. So changes are less high risk.
- Hiding Implementations/Data Because your source files will be compiled into binaries/libraries, when you share your headers and librar (.so or .a file) you will have hidden part of your implementation from the end user.