What am I missing in GotW #28: The Fast Pimpl Idiom?

Viewed 197

"GotW #28" is an old article written by Herb Sutter. In that article, Herb explains why the following design is a bad idea (I took the liberty to replace assert with static_assert, though):

// file y.h
class Y
{
    /*...*/
    static const size_t sizeofx = /*some value*/;
    char x_[sizeofx];
};

// file y.cpp
#include "x.h"

Y::Y() {
    static_assert( sizeofx >= sizeof(X), "Please, fix Y::sizeofx" );
    new (&x_[0]) X;
}

Y::~Y()
{
    (reinterpret_cast<X*>(&x_[0]))->~X();
}

Leaving aside the questions of alignment (std::aligned_storage wasn't around at the time) and maintenance, I'd like to focus on the following point:

Herb Sutter claims that writing a safe (considering exception safety) Y::operator=() and safe Y::~Y() is a lot more trouble than it's worth. And this is something I don't get.

What trouble is he talking about? What's wrong with the destructor above? And what's wrong with a simple assignment like this:

Y& Y::operator=(const Y& other)
{
    *reinterpret_cast<X*>(&x_[0]) = *reinterpret_cast<const X*>(&other.x_[0]);
    return *this;
}

Given that Y class has neither base classes no other members, I would say that exception guarantees of Y::operator=(const Y&) and Y::~Y() will be those of corresponding X::operator=(const X&) and X::~X(). But Herb Sutter hinted that there's more trouble to it...

What am I missing?

0 Answers
Related