Re: Rebirthing an object... just making sure
Alf P. Steinbach wrote:
[string of misunderstandings]
Uhm -- it's Kai-Uwe. (The "Uwe" is not a middle name.)
with no exception and T() constructing a valid object, p is a valid
pointer to that object -- /no matter what that memory was used for
earlier/, garbage, similar object, whatever, that earlier bit usage
history /does not matter/.
Unfortunately (and since I was burnt by [3.8/7], I really mean it), [3.8/7]
explicitly says that the history does matter. In particular, according to
Base * ptr = new Derived;
ptr->Base::~Base(); // only destroy the Base subobject
::new (ptr) Base; // recreate a Base subobject
has undefined behavior.
Now, I might be overly careful with regard to [3.8/7] since I have a history
with that clause. So, you could be right and I could be misunderstanding
something. However, adding emphasis to your claims will not help me learn.
So please bear with me and help me sorting this out.
Yes, gladly, but I wasn't adding emphasis as a kind of loud voice, I
emphasized what to my mind was and is important for you to understand.
char* buf = new char[sizeof(T)];
// Here copying whatever values you want into buf.
T* p = static_cast<T*>( static_cast<void*>( buf ) );
T* q = ::new( p ) T();
Essentially your argument implies, in practice (see comment about RREPP
below for why it's not completely formalt), that
assert( ((void*)buf == (void*)p) && (p == q) );
will now fail. For if it doesn't fail, then we have constructed a T
object in memory that possibly could contain exactly the same as after
an explicit destructor call on a T object. Which by your interpretation
of the standard, disregarding RREPP, would be Undefined Behavior.
So standardwise all you need to disprove your interpretation is to prove
that the assertion above doesn't fail, i.e. that the pointers all are
the same address. Let's skip discussing (void*)buf == (void*)p. I
assume you agree: it would be very much ado about nothing.
Then, for p == q, to start with, ?22.214.171.124/2 guarantees that the
single-object standard library placement operator new just returns the
argument pointer, as a void*. Proving that this is also the address
returned by the new expression is more difficult because AFAICS it's not
explicitly stated by the standard. However, first off the storage
provided need not be greater than sizeof(T), and secondly, non-normative
note ?5.3.4/14 states that "The address of the created object will not
necessarily be the same that of the block if the object is an array",
and the above is not an array but a single object.
I guess this is as close to a proof of the assert above that you can get.
And with the assert proven to the degree possible with such vague
standard, you have proven that you can validly construct an object of
type T in memory that contains exactly the same as after an explicit
destruction of a T object, and then have a valid pointer.
And with that proven you have proven that any UB resulting from using an
object placement-constructed in memory that earlier held object of
different type, must come from information held elsewhere about the type
of that object and what address it resided in in memory.
So formally, if your interpretation is correct the only rationale could
be to support Really Really Extremely Phat Pointers (RREPP) that on
assignment checks the dynamic type of the pointed to object and stores
that type information, a typeid-call for every pointer assignment.
Cheers, & hth.,
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
Q: What is the most annoying thing on usenet and in e-mail?