Use the Pimpl Idiom to Reduce Compilation Time and Enhance Encapsulation

Use the Pimpl Idiom to Reduce Compilation Time and Enhance Encapsulation

ong compilation time is an issue of concern for many large-scale C++ projects. In some cases, a typical build cycle takes up a whole night or an entire weekend. This problem is aggravated by the fact that changes in the implementation details of a single infrastructure class trigger a wholesale recompilation of numerous classes that refer to the modified class. This solution will show you how to apply the Pimpl idiom to reduce compile-time dependencies, and thus reduce compilation time. Another benefit of using this technique is a higher level of encapsulation.

How can you avoid a wholesale recompilation when a change in the implementation details of a frequently-used class has taken place?

Use the Pimpl idiom, also known as the compiler-firewall idiom.

Presenting the Problem
Suppose you are designing a custom string class that is used in a large-scale project. This means that dozens of other classes and modules will depend on the header file in which the string class is defined. Here’s a slightly contrived implementation of this class for demonstration purposes:

//+++ file String.h#include #include #include "Lock.h"class String{public: String(); ~String();//..copy ctor et al. std::size_t length() const; std::ostream & operator << (std::ostream& s) const; //...private: std::vector  vc; std:size_t len; Lock lck; //multithreading support};

Each client that uses this class has to #include the header String.h. The problem is that whenever you change the private section of this class, every piece of code that uses this class has to be recompiled. Not only does this dependency increase compilation time considerably, it also compromises encapsulation.

Remove Redundant #includes
String.h #includes three other headers. The first two are known to take relatively long to compile because they are made up of several other internal headers and template code. Notice, however, that String.h contains only declarations of its member functions. Therefore, you don’t really need the bulky header to compile it. Replace it with the lightweight header . Since String.h is #included in multiple source files, the overall effect can be noticeable.

Is it possible to remove and Lock.h as well? Yes, it is.

Apply the Pimpl Idiom
Originally introduced by James Coplien in 1992, the Pimpl idiom has undergone several revisions and name changes. The name Pimpl itself stands for “impl” with the prefix “p”, following the Hungarian naming convention. Pimpl is a method of hiding implementation details by moving private members (both data and functions) of a class into an internal private struct.

In String.h, you provide only forward declaration of this internal struct (called StringImpl in this example) and add an opaque pointer to it. The modified String.h file now looks like this:

 //+++ file String.h after applying the Pimpl idiom#include class String{public: String (); ~String(); //... std::size_t length() const; std::ostream & operator << (std::ostream& s) const; //...private: struct StringImpl; //fwd declaration of internal struct StringImpl * pimpl; //opaque pointer};

In the corresponding String.cpp file (which, unlike String.h, is compiled only once), you add the definition of struct StringImpl along with the rest of String's member functions:

//+++file String.cpp#include #include "Lock.h"#include "String.h"struct String::StringImpl{ std::vector vc; std::size_t len; Lock lck;};String::String(): pimpl (new String::StringImpl) {}String::~String() {delete pimpl; }//..additional member functions

Every String object allocates its own StringImpl object dynamically during construction. String's member functions access the StringImpl members using the pointer pimpl:

//+++file String.cppstd::size_t String::length() const{ return pimpl->len;}

Now you can modify StringImpl (say by replacing the vector data member with char *) without recompiling the entire project.

A Pimpl in Time
In essence, the Pimpl idiom moves code from a header file that gets compiled several times (once for each translation unit that #includes it), into a single source file which gets compiled only once. The two major advantages of this are:

  • You can freely change the implementation details of String without having to recompile code that uses that class.
  • Datatypes that are used only as private members (in this example: std::vector, Lock and std::size_t) need no longer be defined in String.h. This means that you can remove extra #includes from String.h, thus reducing compilation time.

If the original class contained many private members, and its header file is #included in numerous, separately-compiled files, applying this idiom can reduce compilation time significantly. That said, you already know that there's no such thing as a free lunch. While a Pimpled class may reduce compilation time and enhance encapsulation, it exacts performance penalties:

  • Each construction and destruction allocates and release memory dynamically.
  • String accesses its hidden data members using a pointer, whereas the non-Pimpled version accesses them directly.

Therefore, it's always best to experiment with a few key-classes in a project and learn how this affects your project's build-time.

Share the Post:
Heading photo, Metadata.

What is Metadata?

What is metadata? Well, It’s an odd concept to wrap your head around. Metadata is essentially the secondary layer of data that tracks details about the “regular” data. The regular

XDR solutions

The Benefits of Using XDR Solutions

Cybercriminals constantly adapt their strategies, developing newer, more powerful, and intelligent ways to attack your network. Since security professionals must innovate as well, more conventional endpoint detection solutions have evolved

AI is revolutionizing fraud detection

How AI is Revolutionizing Fraud Detection

Artificial intelligence – commonly known as AI – means a form of technology with multiple uses. As a result, it has become extremely valuable to a number of businesses across

AI innovation

Companies Leading AI Innovation in 2023

Artificial intelligence (AI) has been transforming industries and revolutionizing business operations. AI’s potential to enhance efficiency and productivity has become crucial to many businesses. As we move into 2023, several

data fivetran pricing

Fivetran Pricing Explained

One of the biggest trends of the 21st century is the massive surge in analytics. Analytics is the process of utilizing data to drive future decision-making. With so much of

kubernetes logging

Kubernetes Logging: What You Need to Know

Kubernetes from Google is one of the most popular open-source and free container management solutions made to make managing and deploying applications easier. It has a solid architecture that makes