[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:

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_]