Посмотрите на этот простой код:
struct Point {
int x;
int y;
};
void something(int *);
int main() {
Point p{1, 2};
something(&p.x);
return p.y;
}
Я ожидаю, что возвращаемое значение main
может быть оптимизировано до return 2;
, так как something
не имеет доступа к p.y
, он получает только указатель на p.x
.
Но ни один из основных компиляторов не оптимизирует возвращаемое значение от main
до 2
. Godbolt .
Есть ли в стандарте что-то, что позволяет something
модифицировать p.y
, если мы только даем доступ к p.x
? Если да, зависит ли это от того, имеет ли Point
стандартное расположение?
Что если я использую something(&p.y);
и return p.x;
вместо этого?
Это совершенно четко определено:
void something(int *x) {
reinterpret_cast<Point*>(x)->y = 42;
}
Point
объект (p
) и x
участник являются взаимозаменяемыми указателем, от [basic.compound]:
Два объекта и b взаимозаменяемые указателем если:
- [...]
- каждый - объект стандартного класса макета, и другой первый нестатический элемент данных того объекта, или, если объект не имеет никаких нестатических элементов данных, какого-либо подобъекта базового класса того объекта ([class.mem]), или:
- [...]
, Если два объекта являются взаимозаменяемыми указателем, то у них есть тот же адрес, и возможно получить указатель на один от указателя до другого через
reinterpret_cast
.
, Что reinterpret_cast<Point*>(x)
допустимо и действительно заканчивается с указателем, который указывает на p
. Следовательно, изменение это непосредственно прекрасно. Как Вы видите, часть стандартного расположения и первая нестатическая часть элемента данных являются значительными.
, Хотя это не похоже на рассматриваемые компиляторы, оптимизируют дополнительную загрузку, если Вы передаете указатель на p.y
в и возврат p.x
вместо этого.