Рассмотрим следующий фрагмент кода:
union
{
int a;
float b;
};
a = /* ... */;
b = a; // is this UB?
b = b + something;
Является ли назначение одного члена объединения другому действительному?
Рассмотрим следующий фрагмент кода:
union
{
int a;
float b;
};
a = /* ... */;
b = a; // is this UB?
b = b + something;
Является ли назначение одного члена объединения другому действительному?
К сожалению, я верю, что ответ на этот вопрос заключается в том, что эта операция над объединениями указана в С++, хотя самоопределение полностью нормально.
Самоопределение - это четко определенное поведение, если мы посмотрим на проект стандартного раздела С++ 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 в С++, что означает, что вся концепция активный элемент обходит.
Я бы ожидал, что, если исходная и конечная переменные не будут одинакового типа, такая вещь будет Undefined Behavior in C, и я не вижу причин ожидать, что С++ будет обрабатывать ее по-другому. Учитывая long long *x,*y;
, некоторые компиляторы могут обрабатывать оператор типа *x = *y >>8;
, генерируя код, чтобы прочитать все * y, вычислить результат и сохранить его на * x, но компилятор вполне может законно написать код, который скопировал части * y to * x индивидуально. В стандарте четко указано, что если * x и * y являются указателями на один и тот же объект того же типа, компилятор должен убедиться, что никакая часть значения не будет перезаписана, пока эта часть все еще необходима для вычисления, но компиляторы не обязаны справиться с псевдонимом в других ситуациях.