Good evening everyone.
A code snippet will be worth a thousand words :
// Storage suitable for any of the listed instances
alignas(MaxAlign<Base, Derived1, Derived2>::value)
char storage[MaxSize<Base, Derived1, Derived2>::value];
// Instanciate one of the derived classes using placement new
new (storage) Derived2(3.14);
// Later...
// Recover a pointer to the base class
Base &ref = *reinterpret_cast<Base*> (storage);
// Use its (virtual) functions
ref.print();
// Destroy it when we're done.
ref.~Base();
As you can see, I want to access the instance only through its base class, and without actually storing the base class pointer. Note that in the second part, the Derived2
type information will be lost, so I'm left with only storage
and the guarantee that one derived instance is in it.
As placement new never adjusts the destination pointer, this boils down to using reinterpret_cast
to upcast to a base class. Now I know that this is dangerous, since the more appropriate static_cast
adjusts the pointer in some cases. [1]
And indeed, it triggers Undefined Behaviour. You'll find the full code here on Coliru (g++ 4.9.0), where it promptly crashes at runtime. Meanwhile on my PC (g++ 4.8.2), everything is fine. Note that on g++ 4.9, outputting both pointers before calling the functions shows identical values... and works.
So I tried to take the problem backwards : nudging the derived instance so that a pointer to Base
will be equal to storage
.
void *ptr = static_cast<Derived2*>(reinterpret_cast<Base*>(storage));
new (ptr) Derived2(3.14);
No luck. The thing still runs fine on g++ 4.8, and falls in flames on g++ 4.9.
Edit : come to think of it, the above isn't that smart. Because, what if the derived instance ends up before storage
... Ouch.
So my question is : is there a solution to what I'm trying to achieve ? Or, are the cases mentioned at [1] sufficiently well-defined that I can write code that will work with a subset of classes (like, no virtual inheritance) ?