The Pimpl Idiom in practice

Ryan Emerle picture Ryan Emerle · May 9, 2009 · Viewed 20.5k times · Source

There have been a few questions on SO about the pimpl idiom, but I'm more curious about how often it is leveraged in practice.

I understand there are some trade-offs between performance and encapsulation, plus some debugging annoyances due to the extra redirection.

With that, is this something that should be adopted on a per-class, or an all-or-nothing basis? Is this a best-practice or personal preference?

I realize that's somewhat subjective, so let me list my top priorities:

  • Code clarity
  • Code maintainability
  • Performance

I always assume that I will need to expose my code as a library at some point, so that's also a consideration.

EDIT: Any other options to accomplish the same thing would be welcome suggestions.

Answer

Reunanen picture Reunanen · May 9, 2009

I'd say that whether you do it per-class or on an all-or-nothing basis depends on why you go for the pimpl idiom in the first place. My reasons, when building a library, have been one of the following:

  • Wanted to hide implementation in order to avoid disclosing information (yes, it was not a FOSS project :)
  • Wanted to hide implementation in order to make client code less dependent. If you build a shared library (DLL), you can change your pimpl class without even recompiling the application.
  • Wanted to reduce the time it takes to compile the classes using the library.
  • Wanted to fix a namespace clash (or similar).

None of these reasons prompts for the all-or-nothing approach. In the first one, you only pimplize what you want to hide, whereas in the second case it's probably enough to do so for classes which you expect to change. Also for the third and fourth reason there's only benefit from hiding non-trivial members that in turn require extra headers (e.g., of a third-party library, or even STL).

In any case, my point is that I wouldn't typically find something like this too useful:

class Point {
  public:      
    Point(double x, double y);
    Point(const Point& src);
    ~Point();
    Point& operator= (const Point& rhs);

    void setX(double x);
    void setY(double y);
    double getX() const;
    double getY() const;

  private:
    class PointImpl;
    PointImpl* pimpl;
}

In this kind of a case, the tradeoff starts to hit you because the pointer needs to be dereferenced, and the methods cannot be inlined. However, if you do it only for non-trivial classes then the slight overhead can typically be tolerated without any problems.