[class.union] # 11 Classes [[class]](./#class) ## 11.5 Unions [class.union] ### [11.5.1](#general) General [[class.union.general]](class.union.general) [1](#general-1) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L3186) A [*union*](#def:union "11.5.1 General [class.union.general]") is a class defined with the [*class-key*](class.pre#nt:class-key "11.1 Preamble [class.pre]")union[.](#general-1.sentence-1) [2](#general-2) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L3190) In a union, a non-static data member is [*active*](#def:active,union_member "11.5.1 General [class.union.general]") if its name refers to an object whose lifetime has begun and has not ended ([[basic.life]](basic.life "6.8.4 Lifetime"))[.](#general-2.sentence-1) 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[.](#general-2.sentence-2) [*Note [1](#general-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]](class.mem "11.4 Class members")), 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]](class.mem "11.4 Class members")[.](#general-2.sentence-3) — *end note*] [3](#general-3) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L3209) The size of a union is sufficient to contain the largest of its non-static data members[.](#general-3.sentence-1) Each non-static data member is allocated as if it were the sole member of a non-union class[.](#general-3.sentence-2) [*Note [2](#general-note-2)*: A union object and its non-static data members are pointer-interconvertible ([[basic.compound]](basic.compound "6.9.4 Compound types"), [[expr.static.cast]](expr.static.cast "7.6.1.9 Static cast"))[.](#general-3.sentence-3) As a consequence, all non-static data members of a union object have the same address[.](#general-3.sentence-4) — *end note*] [4](#general-4) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L3220) A union can have member functions (including constructors and destructors),but it shall not have virtual ([[class.virtual]](class.virtual "11.7.3 Virtual functions")) functions[.](#general-4.sentence-1) A union shall not have base classes[.](#general-4.sentence-2) A union shall not be used as a base class[.](#general-4.sentence-3) If a union contains a non-static data member of reference type, the program is ill-formed[.](#general-4.sentence-4) [*Note [3](#general-note-3)*: If any non-static data member of a union has a non-trivial copy constructor, move constructor ([[class.copy.ctor]](class.copy.ctor "11.4.5.3 Copy/move constructors")), copy assignment operator, or move assignment operator ([[class.copy.assign]](class.copy.assign "11.4.6 Copy/move assignment operator")), the corresponding member function of the union must be user-provided or it will be implicitly deleted ([[dcl.fct.def.delete]](dcl.fct.def.delete "9.6.3 Deleted definitions")) for the union[.](#general-4.sentence-5) [*Example [1](#general-example-1)*: Consider the following union:union U {int i; float f; std::string s;}; Since std​::​string ([[string.classes]](string.classes "27.4 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[.](#general-4.sentence-7) 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[.](#general-4.sentence-8) — *end example*] — *end note*] [5](#general-5) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L3258) When the left operand of an assignment operator involves a member access expression ([[expr.ref]](expr.ref "7.6.1.5 Class member access")) that nominates a union member, it may begin the lifetime of that union member, as described below[.](#general-5.sentence-1) For an expression E, define the set S(E) of subexpressions of E as follows: - [(5.1)](#general-5.1) If E is of the form A.B,S(E) contains the elements of S(A), and also contains A.B if 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[.](#general-5.1.sentence-1) - [(5.2)](#general-5.2) 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[.](#general-5.2.sentence-1) - [(5.3)](#general-5.3) Otherwise, S(E) is empty[.](#general-5.3.sentence-1) In an assignment expression of the form E1 = E2 that uses either the built-in assignment operator ([[expr.assign]](expr.assign "7.6.19 Assignment and compound assignment operators")) or a trivial assignment operator ([[class.copy.assign]](class.copy.assign "11.4.6 Copy/move assignment operator")), for each element X of S(E1) and each anonymous union member X ([[class.union.anon]](#anon "11.5.2 Anonymous unions")) 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]](basic.life "6.8.4 Lifetime"), 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[.](#general-5.sentence-3) [*Note [4](#general-note-4)*: This ends the lifetime of the previously-active member of the union, if any ([[basic.life]](basic.life "6.8.4 Lifetime"))[.](#general-5.sentence-4) — *end note*] [*Example [2](#general-example-2)*: union A { int x; int y[4]; };struct B { A a; };union C { B b; int k; };int f() { C c; // does not start lifetime of any union member c.b.a.y[3] = 4; // OK, S(c.b.a.y[3]) contains c.b and c.b.a.y;// creates objects to hold union members c.b and c.b.a.yreturn c.b.a.y[3]; // OK, c.b.a.y refers to newly created object (see [[basic.life]](basic.life "6.8.4 Lifetime"))}struct X { const int a; int b; };union Y { X x; int k; };void g() { Y y = { { 1, 2 } }; // OK, y.x is active union member ([[class.mem]](class.mem "11.4 Class members"))int n = y.x.a; y.k = 4; // OK, ends lifetime of y.x, y.k is active member of union y.x.b = n; // undefined behavior: y.x.b modified outside its lifetime,// S(y.x.b) is empty because X's default constructor is deleted,// so union member y.x's lifetime does not implicitly start} — *end example*] [6](#general-6) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L3328) [*Note [5](#general-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*](expr.new#nt:new-expression "7.6.2.8 New [expr.new]")[.](#general-6.sentence-1) — *end note*] [*Example [3](#general-example-3)*: Consider an object u of a union type U having non-static data membersm of type M and n of type N[.](#general-6.sentence-2) 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*](expr.new#nt:new-expression "7.6.2.8 New [expr.new]") as follows:u.m.~M();new (&u.n) N; — *end example*] ### [11.5.2](#anon) Anonymous unions [[class.union.anon]](class.union.anon) [1](#anon-1) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L3349) A union of the form union { [*member-specification*](class.mem.general#nt:member-specification "11.4.1 General [class.mem.general]") } ; is called an [*anonymous union*](#def:anonymous_union "11.5.2 Anonymous unions [class.union.anon]"); it defines an unnamed type and an unnamed object of that type called an [*anonymous union member*](#def:member,anonymous_union "11.5.2 Anonymous unions [class.union.anon]") if it is a non-static data member or an [*anonymous union variable*](#def:variable,anonymous_union "11.5.2 Anonymous unions [class.union.anon]") otherwise[.](#anon-1.sentence-1) Each [*member-declaration*](class.mem.general#nt:member-declaration "11.4.1 General [class.mem.general]") in the [*member-specification*](class.mem.general#nt:member-specification "11.4.1 General [class.mem.general]") of an anonymous union shall either define one or more public non-static data members or be a [*static_assert-declaration*](dcl.pre#nt:static_assert-declaration "9.1 Preamble [dcl.pre]")[.](#anon-1.sentence-2) Nested types, anonymous unions, and functions shall not be declared within an anonymous union[.](#anon-1.sentence-3) The names of the members of an anonymous union are bound in the scope inhabited by the union declaration[.](#anon-1.sentence-4) [*Example [1](#anon-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[.](#anon-1.sentence-5) — *end example*] [2](#anon-2) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L3383) An anonymous union declared in the scope of a namespace with external linkage shall use the [*storage-class-specifier*](dcl.stc#nt:storage-class-specifier "9.2.2 Storage class specifiers [dcl.stc]") static[.](#anon-2.sentence-1) Anonymous unions declared at block scope shall not use a [*storage-class-specifier*](dcl.stc#nt:storage-class-specifier "9.2.2 Storage class specifiers [dcl.stc]") that is not permitted in the declaration of a block variable[.](#anon-2.sentence-2) An anonymous union declaration at class scope shall not have a [*storage-class-specifier*](dcl.stc#nt:storage-class-specifier "9.2.2 Storage class specifiers [dcl.stc]")[.](#anon-2.sentence-3) [3](#anon-3) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L3393) [*Note [1](#anon-note-1)*: A union for which objects, pointers, or references are declared is not an anonymous union[.](#anon-3.sentence-1) [*Example [2](#anon-example-2)*: void f() {union { int aa; char* p; } obj, *ptr = &obj; aa = 1; // error ptr->aa = 1; // OK} 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[.](#anon-3.sentence-2) — *end example*] — *end note*] [*Note [2](#anon-note-2)*: Initialization of unions with no user-declared constructors is described in [[dcl.init.aggr]](dcl.init.aggr "9.5.2 Aggregates")[.](#anon-3.sentence-3) — *end note*] [4](#anon-4) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L3415) A [*union-like class*](#def:class,union-like "11.5.2 Anonymous unions [class.union.anon]") is a union or a class that has an anonymous union as a direct member[.](#anon-4.sentence-1) A union-like class X has a set of [*variant members*](#def:variant_member "11.5.2 Anonymous unions [class.union.anon]")[.](#anon-4.sentence-2) If X is a union, a non-static data member of X that is not an anonymous union is a variant member of X[.](#anon-4.sentence-3) In addition, a non-static data member of an anonymous union that is a member of X is also a variant member of X[.](#anon-4.sentence-4) At most one variant member of a union may have a default member initializer[.](#anon-4.sentence-5) [*Example [3](#anon-example-3)*: union U {int x = 0; union {int k; }; union {int z; int y = 1; // error: initialization for second variant member of U};}; — *end example*]