I l@ve RuBoard Previous Section Next Section

Item 30. The "Fast Pimpl" Idiom

Difficulty: 6

It's sometimes tempting to cut corners in the name of "reducing dependencies" or in the name of "efficiency," but it may not always be a good idea. Here's an excellent idiom to accomplish both objectives simultaneously and safely.

Standard malloc and new calls are relatively expensive.[5] In the code below, the programmer originally has a data member of type X in class Y.

[5] Compared with other typical operations, such as function calls.



// Attempt #1 


//


// file y.h


#include "x.h"


class Y


{


  /*...*/


  X x_;


};





// file y.cpp


Y::Y() {}


This declaration of class Y requires the declaration of class X to be visible (from x.h). To avoid this, the programmer first tries to write:



// Attempt #2 


//


// file y.h


class X;


class Y


{


  /*...*/


  X* px_;


};





// file y.cpp


#include "x.h"


Y::Y() : px_( new X ) {}


Y::~Y() { delete px_; px_ = 0; }


This nicely hides X, but it turns out that Y is used very widely and the dynamic allocation overhead is degrading performance.

Finally, our fearless programmer hits on the "perfect" solution that requires neither including x.h in y.h nor the inefficiency of dynamic allocation (and not even a forward declaration).



// Attempt #3 


//


// file y.h


class Y


{


  /*...*/


  static const size_t sizeofx = /*some value*/;


  char x_[sizeofx];


};





// file y.cpp


#include "x.h"


Y::Y()


{


  assert( sizeofx >= sizeof(X) );


  new (&x_[0]) X;


}


Y::~Y()


{


  (reinterpret_cast<X*>(&x_[0]))->~X();


}


  1. What is the Pimpl Idiom's space overhead?

  2. What is the Pimpl Idiom's performance overhead?

  3. Discuss Attempt #3. Can you think of a better way to get around the overhead?

Note: See Item 29 for more about the Pimpl Idiom.

    I l@ve RuBoard Previous Section Next Section