1

Suppose I have a class X with private implementation Ximpl:

//X.h

class X
{
  void foo();
  //..
private:
  class Ximpl;
  std::unique_ptr<X> x_impl;
}

Then there are several ways to structure the code. Perhaps the most common one is to put everything else into X.cpp file, including Ximpl class declaration, its methods and methods of X class:

//X.cpp

#include"X.h"    

class X::Ximpl
{
  void bar();
  //..
}

void X::Ximpl::bar()
{
  //...
}

void X::foo()
{
  //operate on x_impl
}

However there are other possibilities mentioned in different sources, which can improve the structure of code, but may diminish the advantages of using PIMPL idiom:

  1. Have two cpp files: X.cpp - having only definitions of X methods, and Ximpl.cpp - having definitions from Ximpl class. In this case in X.cpp we'll have to #include "Ximpl.cpp" - which is a bad practice, since cpp file would be compiled twice

  2. Have separate header file Ximpl.h, which defines an implementation class, and put all definitions from both Ximpl and X classes in single X.cpp file. In this case, implementation class is declared in a header file and would be recompiled every time, loosing the certain advantages of PIMPL

  3. Finally, have 4 separate files - header file declaring Ximpl class, second header file declaring X class, and two cpp files with implementations of above 2 classes respectively.

First, is all above correct? And, second, what is the best practice that works and satisfies all requirements? It looks that the first way (just 1 .h and 1 .cpp files) works great, but for large code bases it can quickly become cumbersome to navigate the projects, i.e. single cpp file would contain pimpl class declration, pimpl class definitions and base class definitions.

Oleg Shirokikh
  • 3,447
  • 4
  • 33
  • 61
  • Since the base class and pimpl classes are so tightly coupled, and the base class shouldn't be much other than wrapper functions, I don't see a problem with combining them in the same .cpp. – Mark Ransom Feb 12 '15 at 23:36
  • With modern platforms, the build process speed of one file versus two is negligible. I suggest picking a style and sticking with it. – Thomas Matthews Feb 12 '15 at 23:41
  • The best practice is always the simplest one. If you are not giving away your headers to library users, don't do PIMPL. If you need PIMPL and both classes fit nicely into a single .cpp file, do it. If you figure you need to promote your implementation class to a full class (one that is not just the implementation detail of another), do it and use four files. But in this later case, you can argue that you are not doing PIMPL anymore. – cmaster - reinstate monica Feb 13 '15 at 00:02
  • @cmaster As far as I understand it, PIMPL is about reducing dependencies: The user of `X` is not dependent on anything that `Ximpl` uses. That does not change when you split it up into 4 files: A user of `X` does not have to include the header file where `Ximpl` is defined. – dyp Feb 13 '15 at 00:34
  • @dyp Dependency reduction is only one aim of PIMPL, the other is to make it impossible for users of the class to mess around with its implementation. The dependency reduction is only an issue if the implementation class uses some heavy templates / stuff that's implemented via many `inline` functions. But yes, you are right I didn't think about the dependency reduction aspect of PIMPL. – cmaster - reinstate monica Feb 13 '15 at 06:25
  • @cmaster I don't quite see how PIMPL protects the implementation of a class. Would you mind elaborating on that? -- The dependency reduction I was alluding to is mostly about the dependency on the object layout of data members. The header file where `X` is defined in is independent from the data members of the PIMPL class. Those data members can have types defined in other header files, such that the user of `X.h` does *not* need to include those other headers. – dyp Feb 13 '15 at 17:37
  • @dyp Yes, I understand the effect of the dependency reduction. The protection of the class implementation is achieved by never handing the implementation class' definition to a user of the code. He can't mess around with data members he doesn't know that they exist. Of course, this protection is only of real importance when the class is part of a library. Within a project, a `private` should be enough to keep programmers of other classes away from it (and if it's not, you should keep the programmers away from your code). – cmaster - reinstate monica Feb 13 '15 at 17:51
  • @cmaster For a library, it's not necessarily to give *all* header files to library users. Hence, you could for example publish `X.h` but choose not to publish `Ximpl.h`. For development purposes, you can keep `X.h` in some common public header folder (structure), and `Ximpl.h` closer to the source files. Within a project, I don't see how putting something in a source file helps protecting it, as opposed to putting it in a header file. Both can be modified by programmers with sufficient access rights. – dyp Feb 13 '15 at 19:15
  • @cmaster - Another aim of PIMPL is to solve cross-boundary memory allocation issues. E.g. if your class has STL stuff, you'll be in trouble working with such class from a library, however if you access all members through the methods operating on pointer to PIMPL - it's safe even with STL. Regarding putting the declarations of PIMPL in .h file - isn't this ruining the purpose of PIMPL - to allow quick compilation if the only change is in implementation - and entire implementation sits in .cpp file. So only it's getting recompiled. – Oleg Shirokikh Feb 13 '15 at 21:30
  • @user2028058 Afaik, the memory allocation issue is specific to Windows, on linux the problem does not exist. So, whether you need PIMPL for that depends on which platform you develop on. Concerning the compilation speed of your .h files: The compiler does not generate code for a template unless that code is called. As such, putting an `std::vector<>` variable into a header will not take as much time as putting the code that uses that variable in the header. The only drawback of using the full set of four files to implement PIMPL is that it bloats your source code directory. – cmaster - reinstate monica Feb 14 '15 at 10:06

0 Answers0