Is there a (semantic) difference between the return value of placement new and the casted value of its operand?
struct Foo { ... };
char buffer[...];
Foo *a = new(buffer) Foo;
Foo *b = reinterpret_cast<Foo *>(buffer);
Does a
and b
differ in some way?
EDIT: Based on DaBler's comment, this question tells that there is a difference, if const/reference members used: Placement new and assignment of class with const member
So, my little-bit updated question: Does a
and b
differ in any way, if Foo
doesn't have const or reference members?
Access through
a
is legal whileb
is not. From [basic.compound]They are not the same object, not unions and not subobjects to each other, therefore not pointer-interconvertible.
Note [expr.reinterpret.cast] only guarantees
reinterpret_cast<char*>(b) == buffer
.Only
a
can safely be used to directly access theFoo
object created by the placement new-expression (which we'll callx
for ease of reference). Usingb
requiresstd::launder
.The value of
a
is specified in [expr.new]/1:The value of
a
is therefore "pointer tox
". This pointer, of course, can safely be used to accessx
.reinterpret_cast<Foo*>(buffer)
applies the array-to-pointer conversion tobuffer
(see [expr.reinterpret.cast]/1). The resulting value after the conversion is applied is "pointer to the first element ofbuffer
". This is areinterpret_cast
of an object pointer to an object pointer of a different type, and is defined as equivalent tostatic_cast<Foo*>(static_cast<void*>(buffer))
by [expr.reinterpret.cast]/7.The inner cast to
void*
is actually an implicit conversion. Per [conv.ptr]/2,Therefore the inner cast yields a
void*
with the value "pointer to the first element ofbuffer
".The outer cast is governed by [expr.static.cast]/13, which I've lightly reformatted into bullet points:
Assuming that
buffer
is suitably aligned (you'd be in trouble well before this point if it's not), the first bullet is inapplicable. The second bullet is likewise inapplicable as there's no pointer-interconvertiblity here. It follows that we hit the third bullet - "the pointer value is unchanged by the conversion" and remains "pointer to the first element ofbuffer
".Thus,
b
does not point to theFoo
objectx
; it points instead to the firstchar
element ofbuffer
, even though its type isFoo*
. It therefore cannot be used to accessx
; attempting to do so yields undefined behavior (for the non-static data member case, by omission from [expr.ref]; for the non-static member function case, by [class.mfct.non-static]/2).To recover a pointer to
x
fromb
,std::launder
can be used: