Kai-Uwe Bux wrote:
You raise good points. Let me respond as best I can.
This goes by the technical term of "a hack." It causes undefined
behavior, because an existing object never has its destructor called,
but you are then reusing the memory where that undestructed object
sits.
Where do you find that this is undefined behavior? From the standard:
[3.8/4] A program may end the lifetime of any object by reusing the
storage which the object occupies or by explicitly calling the destructor
for an object of a class type with a non-trivial destructor. For an object
of a class type with a non-trivial destructor, the program is not required
to call the destructor explicitly before the storage which the object
occupies is reused or released; however, if there is no explicit call to
the destructor or if a delete-expression (5.3.5) is not used to release
the storage, the destructor shall not be implicitly called and any program
that depends on the side effects produced by the destructor has undefined
behavior.
The way I read this says: you can reuse the memory that an object occupies
without calling its destructor, provided you are not relying on side
effects of a possibly non-trivial destructor in the program.
This just may be an example of my saying the glass is half-empty, and
you saying the glass is half full. The section you quote says, in
effect, if an object has a non-trivial destructor, then the failure to
call the destructor is undefined unless there is nothing that relies,
expressly or implicitly, on the behavior of that destructor. To me,
that means undefined behavior. You say, quite reasonably, that so long
as an object has a trivial destructor, or at least there is nothing
relying on the behavior of the structure, doing this is well defined.
To me, those constraints are too great - they are enough for me to say,
"because using this idiom will often result in undefined behavior, one
should not use this idiom." Among other things, I would think that the
compiler may make certain aliasing assumptions when it optimizes that
will turn out not to be true.
This maybe true. I am not sure though. The way I see it, the OP reuses the
memory occupied by a BaseImp subobject inside an Impl object and constructs
a new BaseImp object in there. It is quite possible that this invalidates
the ambient Impl object, but I don't know what the standard says about
this. Do you happen to know a reference?
No offhand. But consider: the compiler may add padding to BaseImp and
may not add that same padding to to Impl. The compiler could
conceivably overwrite that padding. But perhaps I am wrong about this.
But in any case, here's an analogy - the OP is creating the moral
equivalent of the following:
union { BaseImpl base; Impl impl };
Doing that is generally undefined except for POD. (Perhaps I am
overstating that a bit, but you know what I mean). At the very least,
it illustrates that this is a hack.
Best regards,
Tom