Is it possible to use placement-new to change the type of a polymorphic object? if not, what exactly in the standard prohibits it?
Consider this code:
#include <new>
struct Animal {
Animal();
virtual ~Animal();
virtual void breathe();
void kill();
void *data;
};
struct Dead: Animal {
void breathe() override;
};
void Animal::kill() {
this->~Animal();
new(this) Dead;
}
Is calling "kill" ever legal?
Update: Early comments do not address the (il)legality according to the standard of the programming technique shown here of changing the type of an object by explicit call to destructor and applying placement-new for a new object compatible.
Because there is interest in why would anyone would like to do this, I can mention the use case that led me to the question, although it is not relevant to the question I am asking.
Imagine you have a polymorphic type hierarchy with several virtual methods. During the lifetime of the object, things happen that can be modeled in the code as the object changing its type. There are many perfectly legal ways to program this, for example, keeping the object as a pointer, smart or not, and swapping in a copy of the other type. But this may be expensive: One has to clone or move the original object into another one of a different type just to swap the new in.
In GCC, Clang, and others, changing the type of an object can be as cheap as to simply changing the virtual table pointer, but in portable C++ this is not possible except by constructing in-place an object of a new type.
In my original use case, the object could not be held as a pointer either.
I would like to know what the standard says on the subject of reusing memory.
In your example, a call to
kill()
itself may be valid (if it so happens thatsizeof(Animal)==sizeof(Dead)
, which I don't think is guaranteed), but most attempts to useAnimal*
pointer orAnimal&
lvalue through which that call was made would trigger undefined behavior by way of accessing the object whose lifetime has ended. Even assuming that the stars align andAnimal
subobject ofDead
perfectly overlays the original location of the original stand-aloneAnimal
object, such a pointer or lvalue is not considered to refer to the former, but to the now-expired latter.