[class.union.general] (original) (raw)
11 Classes [class]
11.5 Unions [class.union]
11.5.1 General [class.union.general]
In a union, a non-static data member is activeif its name refers to an object whose lifetime has begun and has not ended ([basic.life]).
At most one of the non-static data members of an object of union type can be active at any time, that is, the value of at most one of the non-static data members can be stored in a union at any time.
[Note 1:
One special guarantee is made in order to simplify the use of unions: If a standard-layout union contains several standard-layout structs that share a common initial sequence ([class.mem]), and if a non-static data member of an object of this standard-layout union type is active and is one of the standard-layout structs, it is permitted to inspect the common initial sequence of any of the standard-layout struct members; see [class.mem].
— _end note_]
The size of a union is sufficient to contain the largest of its non-static data members.
Each non-static data member is allocated as if it were the sole member of a non-union class.
[Note 2:
As a consequence, all non-static data members of a union object have the same address.
— _end note_]
A union can have member functions (including constructors and destructors),but it shall not have virtual ([class.virtual]) functions.
A union shall not have base classes.
A union shall not be used as a base class.
If a union contains a non-static data member of reference type the program is ill-formed.
[Example 1:
Consider the following union:union U { int i;float f; std::string s;};
Since std::string ([string.classes]) declares non-trivial versions of all of the special member functions, U will have an implicitly deleted default constructor, copy/move constructor, copy/move assignment operator, and destructor.
To use U, some or all of these member functions must be user-provided.
— _end example_]
When the left operand of an assignment operator involves a member access expression ([expr.ref]) that nominates a union member, it may begin the lifetime of that union member, as described below.
For an expression E, define the set S(E)of subexpressions of Eas follows:
- If E is of the form A.B,S(E) contains the elements of S(A), and also contains A.Bif B names a union member of a non-class, non-array type, or of a class type with a trivial default constructor that is not deleted, or an array of such types.
- If E is of the form A[B]and is interpreted as a built-in array subscripting operator,S(E) is S(A) if A is of array type,S(B) if B is of array type, and empty otherwise.
- Otherwise, S(E) is empty.
In an assignment expression of the form E1 = E2that uses either the built-in assignment operator ([expr.ass]) or a trivial assignment operator ([class.copy.assign]), for each element X of S(E1), if modification of X would have undefined behavior under [basic.life], an object of the type of X is implicitly created in the nominated storage; no initialization is performed and the beginning of its lifetime is sequenced after the value computation of the left and right operands and before the assignment.
[Note 4:
This ends the lifetime of the previously-active member of the union, if any ([basic.life]).
— _end note_]
[Example 2: union A { int x; int y[4]; };struct B { A a; };union C { B b; int k; };int f() { C c; c.b.a.y[3] = 4; return c.b.a.y[3]; } struct X { const int a; int b; };union Y { X x; int k; };void g() { Y y = { { 1, 2 } }; int n = y.x.a; y.k = 4; y.x.b = n; } — _end example_]
[Note 5:
In cases where the above rule does not apply, the active member of a union can only be changed by the use of a placement new-expression.
— _end note_]
[Example 3:
Consider an object u of a union type U having non-static data membersm of type M and n of type N.
If M has a non-trivial destructor and N has a non-trivial constructor (for instance, if they declare or inherit virtual functions), the active member of u can be safely switched from m ton using the destructor and placement new-expression as follows:u.m.~M();new (&u.n) N;
— _end example_]