Хотя это правда , что поведение определено корректно - это не правда , что компиляторы могут «оптимизировать для сопзЬ» в том смысле , что вы имеете в виду.
То есть компилятору не разрешается предполагать, что только из-за того, что параметр является a const T* ptr, указанная память ptrне будет изменена через другой указатель. Указатели даже не должны быть равны. Это constобязательство, а не гарантия - ваше обязательство (= функция) не вносить изменения через этот указатель.
Чтобы действительно иметь такую гарантию, вам нужно пометить указатель restrictключевым словом. Таким образом, если вы скомпилируете эти две функции:
int foo(const int* x, int* y) {
int result = *x;
(*y)++;
return result + *x;
}
int bar(const int* x, int* restrict y) {
int result = *x;
(*y)++;
return result + *x;
}
foo()функция должна прочитать дважды из x, в то время как bar()только нужно прочитать его один раз:
foo:
mov eax, DWORD PTR [rdi]
add DWORD PTR [rsi], 1
add eax, DWORD PTR [rdi] # second read
ret
bar:
mov eax, DWORD PTR [rdi]
add DWORD PTR [rsi], 1
add eax, eax # no second read
ret
Смотрите это в прямом эфире GodBolt.
restrictявляется только ключевым словом в C (начиная с C99); к сожалению, он до сих пор не введен в C ++ (по плохой причине, так как его сложнее ввести в C ++). Многие компиляторы поддерживают его, как, впрочем, и __restrict.
Итог: компилятор должен поддерживать ваш «эзотерический» вариант использования при компиляции f()и не будет иметь никаких проблем с ним.
Смотрите этот пост относительно вариантов использования для restrict.
constне является «вашим обязательством (= функция) не вносить изменения через этот указатель». Стандарт C позволяет функции удалятьconstчерез приведение, а затем изменять объект в результате. По сути,constэто просто рекомендация и удобство для программиста, помогающее избежать непреднамеренного изменения объекта.