The PIMPL idiom

The purpose

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

The story behind

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.

 

Brief example

// foo.h - header file
#include <memory>
class foo
{
    public:
        foo();
        ~foo();
        foo(foo&&);
        foo& operator=(foo&&);
    private:
        class impl;
        std::unique_ptr 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()}
{
    pimpl->do_internal_work();
}
foo::~foo() = default;
foo::foo(foo&&) = default;
foo& foo::operator=(foo&&) = default;

 

Programator, împătimit al tehnologiei. Absolvent al Universității Politehnica din Timișoara, in prezent dezvoltator de soluții software C++/Web

Leave a reply:

Your email address will not be published.