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ęć ptr
nie zostanie zmieniona za pomocą innego wskaźnika. Wskaźniki nawet nie muszą być równe. const
Jest 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 restrict
sł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.
restrict
jest 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
.
const
nie jest „obowiązkiem użytkownika (= funkcji), aby nie dokonywać zmian za pomocą tego wskaźnika”. Standard C pozwala na usunięcie funkcjiconst
za pomocą rzutowania, a następnie zmodyfikowanie obiektu w wyniku. Zasadniczoconst
jest jedynie poradą i wygodą dla programisty, aby pomóc uniknąć przypadkowej modyfikacji obiektu.