//
//  (C) Porkolab 2003
//
//  A.8.3.
//   
//  Fast PIMPL:


PIPML has some drawbacks, like allocating/deallocating
objects in the heap, which could be slow.


What about this "optimalization"


// file: y.h

#include "x.h"

class Y
{
    //...
    X x_;
};


// file: y.cpp

Y::Y() { }


========= ver 2 =============

// file y.h

class X;

class Y
{
    //...
    X *px_;
};


// file: y.cpp

Y::Y() : px_(new X) { }
~Y::Y() { delete px_; }


========= ver 3 ===============

// file: y.h

class Y
{
    //...
    static const size_t sizeofx = /* ... */;
    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();
}


Questins:

- What is the Pimpl space overhead
- What is the performance overhead
- What about the 3rd version


Space overhead:


#include <iostream>

using namespace std;

struct X {
    char c;
    struct XImpl *pimpl_;
};
struct XImpl { char c; };

int main()
{
    cout << sizeof(XImpl) << '\t' << sizeof(X) << endl;
    return 0;
}

// result: 1    8



Runtime overhead:

- allocation/deallocation cost: relativelly expensive
- indirect access of private members (+ back pointer)

Critiques of 3rd "solution":

1. alignment problems: new guaranties,
   that object will align properly,
   char[] buffers doesn't!

2. X must not use the default assignment operator=()

3. If sizeof(XImpl) grows greater then sizeofx,
   we need to update the source.



// file x.h

class X
{
    //...
    struct XImpl *pimpl_;
};

// file x.cpp

#include "x.h"

struct XImpl
{
    // private stuff here ...
    static void *operator new(size_t)   { /*...*/ }
    static void *operator delete(void*) { /*...*/ }
};

X::X() : pimpl_( new XImpl ) { }
X::~X() { delete pimpl_; pimpl_ = 0; }