You know, I thought about this and your objection to PIMPL for a bit.
I have an ugly hack I use sometimes for cases like this, where I resent paying the indirection penalty. Though usually my complaint is with calling new, and not with the pointer dereference. I present my ugly hack thusly:
// IHaveOpaqueData.h
class IHaveOpaqueData {
public:
// To make sure there are no alignment problems, maybe ::std::uin64_t
typedef maximally_aligned_type_t internal_data_t[32]; // Some size I hope is big enough
void iCanHazMemberFunction();
// ...
private:
internal_data_t data;
};
// IHaveOpaqueData.cpp
#include <boost/static_assert.hpp>
namespace { // Hide it in an anonymous namespace
struct RealData {
int icanhazmembervariable_;
double icanhazdoublevariable_;
};
BOOST_STATIC_ASSERT(sizeof(RealData) < sizeof(IHaveOpaqueData::internal_data_t);
}
void IHaveOpaqueData::iCanHazMemberFunction()
{
// Use a reference to help the optimize make the right decision
RealData &datathis = *(reinterpret_cast<RealData *>(&(this->data)));
datathis.icanhazmembervariable_ = datathis.icanhazdoublevariable_;
}
Yes, this is ugly. BOOST_STATIC_ASSERT (or if you have a C++[01]x compiler the static_assert keyword) helps make it not be a total disaster. There may be a clever way to use unions to mitigate some of the twitchiness I have over alignment issues as well.