12 Classes [class]

12.3 Unions [class.union]

В объединении нестатический член данных - это 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 noteExample:

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 noteExample: u union U m M n N M N u m n new-expression

u.m.~M();
new (&u.n) N;

end example]

12.3.1 Anonymous unions [class.union.anon]

Союз формы

union { member-specification } ;

называется anonymous union; он определяет безымянный тип и безымянный объект этого типа, называемый anonymous union object. Каждый member-declarationв member-specification анонимном союзе должен либо определить нестатический элемент данных или быть static_assert-declaration. [ Note: Вложенные типы, анонимные объединения и функции не могут быть объявлены в анонимном объединении. ] Имена членов анонимного объединения должны отличаться от имен любых других объектов в области, в которой объявлено анонимное объединение. В целях поиска имени после определения анонимного объединения члены анонимного объединения считаются определенными в области, в которой объявлено анонимное объединение. [end noteExample:

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