Хотя это правда , что поведение определено корректно - это не правда , что компиляторы могут «оптимизировать для сопзЬ» в том смысле , что вы имеете в виду.
То есть компилятору не разрешается предполагать, что только из-за того, что параметр является 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
это просто рекомендация и удобство для программиста, помогающее избежать непреднамеренного изменения объекта.