Regarding this code:
#include <string>
int main()
{
union u {
u() { i = 0; }
~u() {}
int i;
std::string s1;
std::string s2;
} u;
new (&u) std::string{};
}
[intro.object]/2 says that
Objects can contain other objects, called subobjects. A subobject can be a member subobject ([class.mem]), a base class subobject ([class.derived]), or an array element. An object that is not a subobject of any other object is called a complete object. If an object is created in storage associated with a member subobject or array element e (which may or may not be within its lifetime), the created object is a subobject of e's containing object if:
— the lifetime of e's containing object has begun and not ended, and
— the storage for the new object exactly overlays the storage location associated with e, and
— the new object is of the same type as e (ignoring cv-qualification).
There is no requirement how an object is created in the storage associated with a member subobject. The code doesn't have to nominate the subobject in the argument of the address-of operator if the subobject is a member of a standard-layout union or the first member of a non-union class object. It is enough to get the address of the containing object to designate the storage of the member subobject in such cases.
«There is no requirement how an object is created», among other things, means that the pointer given to placement new does not have to point to the subobject. Mainly because there could be no object to point to (note, the [intro.object]/2 do not require subobject to be alive). In std-discussion mailing list it was asked, given an object x
of type struct A { unsigned char buf[1]; };
, is there a difference between new (&x) A{}
and new (x.buf) A{}
? And the answer was no, in both cases, x.buf
would provide storage for A{}
. Because
The wording in [intro.object] and [basic.life] concern themselves with the storage address represented by a pointer, not the object to which it points.
[class.union]/1 swears that «At most one of the non-static data members of an object of union type can be active at any time».
Which one became active in the code above, s1
or s2
?
std::string
types. – Kravitss1
ands2
have a common initial sequence which covers their entire sequence of data members, therefore they are indistinguishable? – Draftsmanstd::string
withdouble
and this note won't apply. – Kravitss1
ors2
becomes active? It says "at most one ..." – Turncoatu.s1
oru.s2
has even not begun), and even in that case, they are definitely two objects. – Turncoat