Open Source

Making Pimpl Easy

The Pimpl technique is a useful way to minimize coupling, and separate interface and implementation. Here's a way to simplify Pimpl deployment.

The User Perspective

Let's say we need to write a Pimpl-based Book class with pointer semantics. That is:

a) We want to separate interface and implementation and to hide implementation through the deployment of the Pimpl idiom.b) Our Book class needs to have pointer semantics, i.e. with regard to the underlying data it will behave in the smart-pointer/proxy fashion by allowing shared access to the underlying implementation data.

In that setting the Book class public declaration is quite likely to look like the following:

Thanks to boost::shared_ptr, applying the Pimpl idiom is fairly straightforward as boost::shared_ptr takes care of much of the scaffolding hassle. As a result, the auto-generated destructor, copy constructor and assignment operator suffice and writing the comparison operators is child's play. What more could we wish for? For one thing, lumping the application interface with the infrastructure scaffolding is messy. Moreover, in our (admittedly simple) Book class more than half of the code is the Pimpl-related scaffolding. For one class in isolation that might not look like that big a deal. On a larger scale, analyzing and maintaining twice as much code, mentally separating the application interface from the infrastructure scaffolding, and making sure nothing is forgotten, misused, or misplaced is a tiring exercise and not exactly fun. The following, therefore, seems like a worthwhile improvement:

It is considerably shorter, application-focused and reasonably self-explanatory. It is lean and mean, consisting of nothing but pure application-specific public interface. It does not even need to be a class as there is nothing to restrict access to.

Probably due to the specificity of my task (and/or my programming style) I have been using Pimpl-based classes with pointer semantics (as in the example above) almost exclusively. However, it is certainly not always the right solution. Let's say we needed a Pimpl-based Book class but with value semantics instead. That is, we still want to have interface and implementation properly separated to hide implementation, but our Book class needs to be a class with every Book instance having and managing its own internal data (rather than sharing).

If boost::shared_ptr is an indisputable favorite for Pimpls with pointer semantics, its deployment for Pimpls with value semantics is certain to cause a debate about efficiency, associated overhead, etc. However, writing and getting right a "raw" Pimpl-based class is certainly more involved and possibly more challenging with all things considered. The corresponding declaration might look as follows:

It is still almost three times shorter and it consists of pure application-related public interface. Clean, minimal, elegant.

Both presented pimpl-based declarations (with pointer and value semantics) look almost identical and internal implementations (as we'll see later) are as close. A notable difference is that for value-semantics classes the comparison operators are not freebies as with pointer-semantics classes. Well, the comparison operators are never freebies (they are never auto-generated). However, due to the specificity of classes with pointer semantics those comparison operators can be reduced to pointer comparisons and generalized. Clearly, that's not true with value-semantics classes. If such a class needs to be comparable, we have to write those comparison operators ourselves. That is, for value-semantics classes the comparison operators become part of the user-provided interface. Still, pimpl<> tries to help and adds

bool operator!=(T const& that) const

when

bool operator==(T const& that) const

is supplied.

So far our public for-all-to-see interface looks clean, minimal, and application-related. Our Book class users and those who are to maintain the code later are likely to appreciate that. Let’s have a look at the implementation.

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task.
However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

Video

This month's Dr. Dobb's Journal

This month,
Dr. Dobb's Journal is devoted to mobile programming. We introduce you to Apple's new Swift programming language, discuss the perils of being the third-most-popular mobile platform, revisit SQLite on Android
, and much more!