Const correctness is an important tool for type safety. It allows for catching coding errors at compile time and it documents the code for
maintainers.
Correctly const-qualifying pointers can be tricky because the indirection they add can also be const.
For a pointer X * ptr
, const can be written in three different places:
-
const X * ptr
and X const * ptr
are identical and mean that the X object ptr
points to cannot be
changed.
-
X * const ptr
means that the pointer cannot be changed to point to a different X object.
In a function signature, the first const X * ptr
(or its equivalent X const * ptr
) is the one that will bring
type-safety. It protects against changing the value pointed at.
void externalFunction(int * a, const int * b);
void myfunc() {
int a = 1;
int b = 2;
externalFunction(&a, &b);
// a can now have any value
// We know that b is still '2'
}
This rule detects when a pointer or reference parameter could be made const
void myfunc ( int * param1, // object is modified
const int * param2,
int * param3, // Noncompliant
int * const param4) // Noncompliant: const doesn't qualify what is pointed at.
{
*param1 = *param2 + *param3 + *param4;
}
void increment (int & value,
int & increment) // Noncompliant
{
value += increment;
}
When adding all possible const
qualifications, we get:
void myfunc ( int * param1, // object is modified
const int * param2,
const int * param3,
const int * param4)
{
*param1 = *param2 + *param3 + *param4;
}
void increment (int & value,
const int & increment)
{
value += increment;
}