Files
2025-10-25 03:02:53 +03:00

266 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[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.1General[class.union.general]") is a class defined with the [*class-key*](class.pre#nt:class-key "11.1Preamble[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.1General[class.union.general]") if its name refers to an object
whose lifetime has begun and has not ended ([[basic.life]](basic.life "6.8.4Lifetime"))[.](#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.4Class 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.4Class 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.4Compound types"), [[expr.static.cast]](expr.static.cast "7.6.1.9Static 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.3Virtual 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.3Copy/move constructors")),
copy assignment operator, or
move assignment operator ([[class.copy.assign]](class.copy.assign "11.4.6Copy/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.3Deleted 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.4String 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.5Class 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.19Assignment and compound assignment operators"))
or a trivial assignment operator ([[class.copy.assign]](class.copy.assign "11.4.6Copy/move assignment operator")),
for each element X of S(E1) and
each anonymous union member X ([[class.union.anon]](#anon "11.5.2Anonymous 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.4Lifetime"),
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.4Lifetime"))[.](#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.4Lifetime"))}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.4Class 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.8New[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.8New[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.1General[class.mem.general]") } ;
is called an [*anonymous union*](#def:anonymous_union "11.5.2Anonymous 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.2Anonymous unions[class.union.anon]") if it is a non-static data member or
an [*anonymous union variable*](#def:variable,anonymous_union "11.5.2Anonymous unions[class.union.anon]") otherwise[.](#anon-1.sentence-1)
Each [*member-declaration*](class.mem.general#nt:member-declaration "11.4.1General[class.mem.general]") in the [*member-specification*](class.mem.general#nt:member-specification "11.4.1General[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.1Preamble[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.2Storage 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.2Storage 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.2Storage 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.2Aggregates")[.](#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.2Anonymous 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.2Anonymous 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*]