Этот вопрос является продолжением: добавляет ли UB к указателю "char *", когда он на самом деле не указывает на массив символов?
В CWG 1314 CWG подтвердил, что допустимо выполнять арифметику указателя в объекте стандартной компоновки с использованием указателя unsigned char
. Казалось бы, это подразумевает, что некоторый код, подобный коду в связанном вопросе, должен работать как предполагалось:
struct Foo {
float x, y, z;
};
Foo f;
unsigned char *p = reinterpret_cast<unsigned char*>(&f) + offsetof(Foo, z); // (*)
*reinterpret_cast<float*>(p) = 42.0f;
(Я заменил char
на unsigned char
для большей ясности.)
Однако, похоже, что новые изменения в С++ 17 подразумевают, что этот код теперь UB, если только std::launder
не используется после обоих reinterpret_cast
s. Результат reinterpret_cast
между двумя типами указателей эквивалентен двум static_cast
: первый cv void*
, второй тип указателя назначения. Но [expr.static.cast]/13 подразумевает, что это создает указатель на исходный объект, а не на объект типа назначения, поскольку объект типа Foo
не взаимозаменяем с указателем с unsigned char
объектом unsigned char
в его первом байте Кроме того, объект unsigned char
в первом байте fz
указателя взаимно fz
самим fz
.
Мне трудно поверить, что комитет намеревался изменить ситуацию, которая бы нарушила эту очень распространенную идиому, сделав все использования offsetof
до С++ 17 offsetof
неопределенными.