I l@ve RuBoard | ![]() ![]() |
Item 30. The "Fast Pimpl" IdiomDifficulty: 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.
// 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(); }
Note: See Item 29 for more about the Pimpl Idiom. |
I l@ve RuBoard | ![]() ![]() |