Chociaż prawdą jest, że zachowanie jest dobrze zdefiniowane - to nie prawda, że kompilatory mogą „Optymalizacja dla const” w tym sensie, że masz na myśli.
Oznacza to, że kompilator nie może zakładać, że tylko dlatego, że parametrem jest a const T* ptr, wskazana przez pamięć ptrnie zostanie zmieniona za pomocą innego wskaźnika. Wskaźniki nawet nie muszą być równe. constJest obowiązkiem, a nie gwarancja - obowiązek przez Ciebie (= funkcja) nie dokonywać zmian przez ten wskaźnik.
Aby faktycznie mieć tę gwarancję, musisz oznaczyć wskaźnik restrictsłowem kluczowym. Zatem jeśli skompilujesz te dwie funkcje:
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()funkcja musi czytać dwukrotnie z x, podczas gdy bar()tylko musi ją przeczytać raz:
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
Zobacz to na żywo GodBolt.
restrictjest tylko słowem kluczowym w C (od C99); niestety do tej pory nie został wprowadzony do C ++ (z tego słabszego powodu, że bardziej skomplikowane jest wprowadzenie go w C ++). Jednak wiele kompilatorów trochę to obsługuje __restrict.
Konkluzja: Kompilator musi obsługiwać Twój „ezoteryczny” przypadek użycia podczas kompilacji f()i nie będzie miał z tym żadnego problemu.
Zobacz ten post dotyczący przypadków użycia dla restrict.
constnie jest „obowiązkiem użytkownika (= funkcji), aby nie dokonywać zmian za pomocą tego wskaźnika”. Standard C pozwala na usunięcie funkcjiconstza pomocą rzutowania, a następnie zmodyfikowanie obiektu w wyniku. Zasadniczoconstjest jedynie poradą i wygodą dla programisty, aby pomóc uniknąć przypadkowej modyfikacji obiektu.