Why Should the "Pimpl" Idiom Be Used

Why should the PIMPL idiom be used?

  • Because you want Purr() to be able to use private members of CatImpl. Cat::Purr() would not be allowed such an access without a friend declaration.
  • Because you then don't mix responsibilities: one class implements, one class forwards.

Is the PIMPL idiom really used in practice?

So, I am wondering it this technique is really used in practice? Should I use it everywhere, or with caution?

Of course it is used. I use it in my project, in almost every class.


Reasons for using the PIMPL idiom:

Binary compatibility

When you're developing a library, you can add/modify fields to XImpl without breaking the binary compatibility with your client (which would mean crashes!). Since the binary layout of X class doesn't change when you add new fields to Ximpl class, it is safe to add new functionality to the library in minor versions updates.

Of course, you can also add new public/private non-virtual methods to X/XImpl without breaking the binary compatibility, but that's on par with the standard header/implementation technique.

Data hiding

If you're developing a library, especially a proprietary one, it might be desirable not to disclose what other libraries / implementation techniques were used to implement the public interface of your library. Either because of Intellectual Property issues, or because you believe that users might be tempted to take dangerous assumptions about the implementation or just break the encapsulation by using terrible casting tricks. PIMPL solves/mitigates that.

Compilation time

Compilation time is decreased, since only the source (implementation) file of X needs to be rebuilt when you add/remove fields and/or methods to the XImpl class (which maps to adding private fields/methods in the standard technique). In practice, it's a common operation.

With the standard header/implementation technique (without PIMPL), when you add a new field to X, every client that ever allocates X (either on stack, or on heap) needs to be recompiled, because it must adjust the size of the allocation. Well, every client that doesn't ever allocate X also need to be recompiled, but it's just overhead (the resulting code on the client side will be the same).

What is more, with the standard header/implementation separation XClient1.cpp needs to be recompiled even when a private method X::foo() was added to X and X.h changed, even though XClient1.cpp can't possibly call this method for encapsulation reasons! Like above, it's pure overhead and is related with how real-life C++ build systems work.

Of course, recompilation is not needed when you just modify the implementation of the methods (because you don't touch the header), but that's on par with the standard header/implementation technique.


Is this technique recommended to be used in embedded systems (where the performance is very important)?

That depends on how powerful your target is. However the only answer to this question is: measure and evaluate what you gain and lose. Also, take into consideration that if you're not publishing a library meant to be used in embedded systems by your clients, only the compilation time advantage applies!

Should I use PIMPL everywhere?

If you are writing API/library the question is what is the main advantage for the users of your API and even what IDE and tools they will be using working with your API.
The key points for using PIMPL are:

  • You want to really hide implementation from users (you have great amount of private methods and fields and very simple public interface).
  • You want to abstract them from platform-dependent code.
  • You want to reduce their build time.

You shouldn't use PIMPL when virtual calls or any sort of indirection cost your users too much in operation time of their programs:

  • Sequences of repeated small functions calls (and you can't remove it from API level).
  • Creating and deleting huge amount of small objects (and you can't remove it from API level).

Is pimpl idiom better than using always unique_ptr as member variables?

After a while I have a broader understanding of the problem and finally I can answer to my own question.

It turned out that what I was saying was not completely correct.

In fact in the code below only Bp class is pImpl. If we change Ap to be pImpl aswell we obtain that, if we change Bp.h we need to recompile only Ap.cpp, Bp.cpp, which is the same of the corresponding solution with unique_ptrs.

Said that, I think I can say that the solution with pImpl seems in general better than the solution with unique_ptrs (we just have to pImpl the correct classes!).

For this reason we decided to switch to pImpl idiom as default for our classes.

Using C++ class in Objective-C - Why use PImpl idiom?

The downside is this C++ type MyCPPClass is now in the header file MyObjCClass.h, which other Objective-C classes that use MyObjCClass will have to import. Importing a header is like putting it into the code, so these other Objective-C classes now have C++ in their code, and so will now have to be changed to Objective-C++ files or they won't compile. This is often not desirable, as these other files shouldn't need C++. Although this problem can be solved by declaring your instance variable not in the main class declaration in the header, but in the "extension" (declared like a category but with no name in the parentheses) or in the @implementation, which are in the implementation file, so other classes don't have to import it.

Another problem with C++ classes as instance variables of Objective-C classes is that your C++ object can only be constructed using the default constructor (i.e. no constructor arguments), as there is no way to provide an initializer for an instance variable of an Objective-C class. So if you want to construct it with constructor arguments, you must use pimpl.



Related Topics



Leave a reply



Submit