Можете ли вы присвоить значение одного члена профсоюза другому?

Рассмотрим следующий фрагмент кода:

union
{
   int a;
   float b;
};

a = /* ... */;

b = a;               // is this UB?
b = b + something;

Является ли назначение одного члена объединения другому действительному?

Ответы

Ответ 1

К сожалению, я верю, что ответ на этот вопрос заключается в том, что эта операция над объединениями указана в С++, хотя самоопределение полностью нормально.

Самоопределение - это четко определенное поведение, если мы посмотрим на проект стандартного раздела С++ 1.9 В пункте 15 выполнения программы есть следующие примеры:

void f(int, int);
void g(int i, int* v) {
    i = v[i++]; // the behavior is undefined
    i = 7, i++, i++; // i becomes 9

    i = i++ + 1; // the behavior is undefined
    i = i + 1; // the value of i is incremented

    f(i = -1, i = -1); // the behavior is undefined
}

и самоопределение рассматривается в примере i = i + 1.

Проблема в том, что в отличие от C89 вперед, которая поддерживает тип-punning в С++, это неясно, Мы знаем только, что:

В объединении не более одного нестатического элемента данных могут быть активны в любое время

но поскольку это обсуждение в список рассылки исследовательской группы WG21 UB показывает, что эта концепция не совсем понятна, у нас есть следующие комментарии:

Хотя стандарт использует термин "активное поле", он не определяет его

и указывает на это ненормативное примечание:

Примечание. В общем, нужно использовать явные вызовы деструктора и назначить новые операторы для изменения активного члена объединения. - конец примечания

поэтому нам нужно задаться вопросом:

b = a;

делает b активным членом или нет? Я не знаю, и я не вижу способа доказать это с помощью любой из текущих версий проекта стандарта.

Несмотря на то, что большинство современных компиляторов, например gcc, поддерживает тип-punning в С++, что означает, что вся концепция активный элемент обходит.

Ответ 2

Я бы ожидал, что, если исходная и конечная переменные не будут одинакового типа, такая вещь будет Undefined Behavior in C, и я не вижу причин ожидать, что С++ будет обрабатывать ее по-другому. Учитывая long long *x,*y;, некоторые компиляторы могут обрабатывать оператор типа *x = *y >>8;, генерируя код, чтобы прочитать все * y, вычислить результат и сохранить его на * x, но компилятор вполне может законно написать код, который скопировал части * y to * x индивидуально. В стандарте четко указано, что если * x и * y являются указателями на один и тот же объект того же типа, компилятор должен убедиться, что никакая часть значения не будет перезаписана, пока эта часть все еще необходима для вычисления, но компиляторы не обязаны справиться с псевдонимом в других ситуациях.