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.
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 foo
s 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.