[class.union] (original) (raw)

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, the common initial sequence of any of the standard-layout struct members can be inspected; 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.

[Note 3:

If any non-static data member of a union has a non-trivial copy constructor, move constructor ([class.copy.ctor]), copy assignment operator, or move assignment operator ([class.copy.assign]), the corresponding member function of the union must be user-provided or it will be implicitly deleted ([dcl.fct.def.delete]) for the union.

[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 copy/move constructor and copy/move assignment operator.

The default constructor and destructor of U are both trivial even though std​::​string has a non-trivial default constructor and a non-trivial destructor.

— _end example_]

— _end note_]

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.assign]) or a trivial assignment operator ([class.copy.assign]), for each element X of S(E1) and each anonymous union member X ([class.union.anon]) that is a member of a union and has such an element as an immediate subobject (recursively), 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_]

11.5.2 Anonymous unions [class.union.anon]

A union of the form

is called an anonymous union; it defines an unnamed type and an unnamed object of that type called an anonymous union memberif it is a non-static data member or an anonymous union variable otherwise.

Nested types, anonymous unions, and functions shall not be declared within an anonymous union.

The names of the members of an anonymous union are bound in the scope inhabited by the union declaration.

[Example 1: void f() { union { int a; const char* p; }; a = 1; p = "Jennifer";}

Here a and p are used like ordinary (non-member) variables, but since they are union members they have the same address.

— _end example_]

An anonymous union declared in the scope of a namespace with external linkage shall use the storage-class-specifier static.

Anonymous unions declared at block scope shall not use a storage-class-specifierthat is not permitted in the declaration of a block variable.

[Note 1:

A union for which objects, pointers, or references are declared is not an anonymous union.

[Example 2: void f() { union { int aa; char* p; } obj, *ptr = &obj; aa = 1; ptr->aa = 1; }

The assignment to plain aa is ill-formed since the member name is not visible outside the union, and even if it were visible, it is not associated with any particular object.

— _end example_]

— _end note_]

[Note 2:

Initialization of unions with no user-declared constructors is described in [dcl.init.aggr].

— _end note_]

A union-like class is a union or a class that has an anonymous union as a direct member.

A union-like class X has a set of variant members.

If X is a union, a non-static data member of X that is not an anonymous union is a variant member of X.

In addition, a non-static data member of an anonymous union that is a member of X is also a variant member of X.

At most one variant member of a union may have a default member initializer.

[Example 3: union U { int x = 0;union { int k;};union { int z;int y = 1; };}; — _end example_]