There are several benefits:
- it clarifies your intention: everybody will understand that this variable is not supposed to vary.
- it avoids stupid mistakes, where a typo would have caused your value to change
- it forces discipline: if you use pointers or references to that variable, the compiler will complain if it is a non const pointer or reference, that could lead to subtle errors.
- furthermore, this will encourage discipline in assessing constness of arguments passed by reference or via pointers, which will ultimately avoid more subtle errors and code which is easier to verify.
- it allows the compiler to make assumptions and optimizations, that could otherwise not be made in certain circumstances.
Let me develop the last point with a small and silly example.
The non-const approach:
extern void f(int *p); // function f() takes a non const pointer
int k = 10;
f(&k); // the compiler has to assume that f() could change k
int i = k*k+2*k+1; // the compiler has to make the operation
The relevant part of the assembly looks like:
mov DWORD PTR [rsp+12], 10 // store value in k
mov eax, DWORD PTR [rsp+12] // load the potentially changed k
lea esi, [rax+2] // and make the computation
imul esi, eax
add esi, 1 // here we are ready to display value
Here the compiler has to assume that k could be changed by
f(), because this function is unknown. So the generated code has to make the calculation of
i, even if we'd know that
f() doesn't change the value pointed at.
The const approach:
const int k = 10;
f(const_cast<int*>(&k)); // ATTENTION: we have to be sure about the cast!!
int i = k*k+2*k+1;
First of all, the
const_cast shows that we are taking a risk. So we have to be really sure that
f() will not change the value pointed at (if not it would be undefined behavior).
But the compiler could then generate a much faster code:
mov DWORD PTR [rsp+12], 10
mov esi, 121 // the compiler could make the calculation upfront!
The clean const approach:
const_cast is something risky, and should be avoided if possible. And that's where the second level benefit of using const appears: you become sensitive to this kind of subtleties, and you'll start increasing
const discipline, rewriting the
f() properly by making constness explicit as well:
extern void f(const int *p); // if parameter remains const, tell it !
const int k = 10;
f(&k); // the compiler knows that k will not change
int i = k*k+2*k+1; // the compiler knows it's 121
This code is event better, because not only are you sure that k is constant, but everybody now knows that
f() doesn't change the pointed value, and the compiler can do better constant propagation.
Of course, passing parameters by reference would produce similar results.