Рассмотрим это объединение:
union A{
int a;
struct{
int b;
} c;
};
c
и a
не совместимы с макетом типов, поэтому невозможно прочитать значение b
через a
:
A x;
x.c.b=10;
x.a+x.a; //undefined behaviour (UB)
По поводу пробной версии 1 и пробной версии 2 см. этот вопрос
Пробная версия 3
Теперь давайте используемstd::launder
для чего он не предназначен:
A x;
x.a=10;
auto p = &x.a; //(1)
x.c.b=12; //(2)
p = std::launder(p); //(2')
*p+*p; //(3) UB?
Может ли std::launder
что-то изменить?Согласно [ptr.launder] :
template <class T> constexpr T* launder(T* p) noexcept;
Требуется : p
представляет адрес A байта в памяти.Объект X , срок действия которого совпадает с типом T
, расположен по адресу A .Все байты памяти, которые будут доступны через результат, достижимы через p
(см. Ниже).
Возвращает : значение типа T *
, указывающее на X.
Замечания : вызов этой функции может использоваться в выражении основной константы всякий раз, когда значение ее аргумента может использоваться в выражении основной константы. Байт памяти доступен через значение указателя, которое указывает на объект Y , если он находится внутри хранилища, занятого Y, объекта, который является взаимозаменяемым с Y, или непосредственно в массиве, еслиY является элементом массива.Программа плохо сформирована, если T является типом функции или cv void.
Выделенное жирным шрифтом предложение подчеркивает то, что меня беспокоит.Если p
является недопустимым значением указателя, как может быть доступен любой байт памяти?С другой стороны, при таком чтении std::launder
просто невозможно использовать.
В противном случае значение может p
в (2) быть значением указателя, которое представляет область хранения как естьо чем говорится в «Записке» в [basic.life] :
Если эти условия не выполнены, указатель на новый объект может быть получен изуказатель, представляющий адрес его хранилища путем вызова std::launder
([support.dynamic]).