В объединении нестатический член данных - это active если его имя относится к объекту, lifetime который начался и не закончился. Максимум один из нестатических элементов данных объекта типа объединения может быть активным в любое время, то есть значение не более одного из нестатических элементов данных может быть сохранено в объединении в любое время. [ Note: Одна специальная гарантия дается для упрощения использования объединений: если объединение стандартного макета содержит несколько структур стандартного макета, которые совместно используют a common initial sequence, и если нестатический член данных объекта этого типа объединения стандартного макета является active и является одной из структур стандартного макета, разрешается проверять общую начальную последовательность любого из членов структуры стандартного макета; см [class.mem]. ] — end note
Размер объединения достаточен, чтобы содержать самый большой из его нестатических элементов данных. Каждый нестатический член данных выделяется, как если бы он был единственным членом структуры. [ Note: Объект объединения и его нестатические элементы данных - это pointer-interconvertible ([expr.static.cast]). Как следствие, все нестатические элементы данных объекта объединения имеют один и тот же адрес. ] — end note
Объединение может иметь функции-члены (включая конструкторы и деструкторы), но не должно иметь virtual функций. У союза не должно быть базовых классов. Объединение не должно использоваться в качестве базового класса. Если объединение содержит нестатический элемент данных ссылочного типа, программа имеет неправильный формат. [ Note: Отсутствует default member initializers, если не-статический член данных объединения имеет нетривиальный конструктор по умолчанию ([class.ctor]), copy constructor, конструктор перемещения ([class.copy]), copy assignment operator, move assignment operator, или destructor, соответствующая функция члена союза должна быть предоставленный пользователем или он будет неявно deleted для союза. ] — end note
[ Example: Рассмотрим следующий союз:
union U { int i; float f; std::string s; };
Поскольку std::string объявляет нетривиальные версии всех специальных функций-членов, U будет неявно удален конструктор по умолчанию, конструктор копирования / перемещения, оператор присваивания / перемещения и деструктор. Для использования Uнекоторые или все эти функции-члены должны быть предоставлены пользователем. ] — end example
Когда левый операнд оператора присваивания включает в себя, member access expression который назначает член объединения, он может начать время жизни этого члена объединения, как описано ниже. Для выражения Eопределите набор S(E) подвыражений E следующим образом:
Если E имеет форму A.B, S(E) содержит элементы S(A), а также содержит, A.B если B имена, член объединения неклассового, не-массивного типа или типа класса с тривиальным конструктором по умолчанию, который не удаляется, или массив таких типы.
Если E имеет форму A[B] и интерпретируется как встроенный оператор индексации массива, S(E) is S(A) if A имеет тип массива, S(B) if B имеет тип массива и пусто в противном случае.
В противном случае S(E) пусто.
В выражении присваивания формы , E1 = E2 которая использует либо built-in assignment operator или trivial assignment operator, для каждого элемента X из S(E1), если модификация X будет иметь неопределенное поведение под [basic.life], объектом типа X неявно создаются в выдвинутом хранении; инициализация не выполняется, и начало его жизненного цикла упорядочивается после вычисления значений левого и правого операндов и перед назначением. [На Note: этом заканчивается lifetime членство ранее активного члена союза, если таковой имеется. ] [ — end note Example:
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.y return c.b.a.y[3]; // OK: c.b.a.y refers to newly created object (see [basic.life]) } 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]) 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 ]
[ Note: В общем, new-expressionдля изменения активного члена объединения необходимо использовать явные вызовы деструктора и размещение . ] [ Рассмотрим объект из более типа , имеющей не-статические элементы данных типа и типа . Если есть ненулевая деструктор и имеет нетривиальный конструктор (например, если они объявляют или наследовать виртуальные функции), активный член может быть безопасно переключаются с с использованием деструктора и размещений следующим образом : — end note Example: u union U m M n N M N u m n new-expression
u.m.~M(); new (&u.n) N;
— end example ]
Союз формы
union { member-specification } ;
называется anonymous union; он определяет безымянный тип и безымянный объект этого типа, называемый anonymous union object. Каждый member-declarationв member-specification анонимном союзе должен либо определить нестатический элемент данных или быть static_assert-declaration. [ Note: Вложенные типы, анонимные объединения и функции не могут быть объявлены в анонимном объединении. ] Имена членов анонимного объединения должны отличаться от имен любых других объектов в области, в которой объявлено анонимное объединение. В целях поиска имени после определения анонимного объединения члены анонимного объединения считаются определенными в области, в которой объявлено анонимное объединение. [ — end note Example:
void f() { union { int a; const char* p; }; a = 1; p = "Jennifer"; }
Здесь a и p используются как обычные (не являющиеся членами) переменные, но поскольку они являются членами объединения, у них одинаковый адрес. ] — end example
Анонимные объединения, объявленные в именованном пространстве имен или в глобальном пространстве имен, должны быть объявлены static. Анонимные объединения, объявленные в области видимости блока, должны быть объявлены с любым классом хранения, разрешенным для переменной области видимости блока, или без класса хранения. Класс хранения не допускается в объявлении анонимного объединения в области действия класса. Анонимный союз не может иметь членов или (пункт ). Анонимный союз не должен иметь функций-членов. private protected [class.access]
Объединение, для которого объявлены объекты, указатели или ссылки, не является анонимным объединением. [ Example:
void f() { union { int aa; char* p; } obj, *ptr = &obj; aa = 1; // error ptr->aa = 1; // OK }
Присвоение plain aa неверно сформировано, поскольку имя члена не видно за пределами объединения, и даже если оно было видимым, оно не связано с каким-либо конкретным объектом. ] [ Инициализация объединений без конструкторов, объявленных пользователем, описана в . ] — end example Note: [dcl.init.aggr] — end note
A union-like class - это объединение или класс, прямым членом которого является анонимный союз. Класс, подобный объединению, X имеет набор variant members. Если X это объединение, нестатический член данных, X который не является анонимным объединением, является его вариантным членом X. Кроме того, нестатический член данных анонимного союза, который является членом, X также является вариантным членом X. Не более одного варианта члена объединения может иметь инициализатор члена по умолчанию. [ Example:
union U {
int x = 0;
union {
int k;
};
union {
int z;
int y = 1; // error: initialization for second variant member of U
};
};
— end example ]