Const and Const Correctness

const is a keyword we can use to make variables "constant", meaning their values can not be changed after initialization. We can also use const for pointers, function parameters and member functions.

The use of const is as much about properly documenting the intention behind our code as it is enforcing program safety.


Const correctness

The idea behind const correctness is to more clearly express the intent of our code to anyone reading it (compiler included).

Guidelines

  • Use const with variables that should not be modified after initialization
  • Pass function parameters as const references if the functions do not need to modify them
  • Declare member functions as const if they do not modify the object on which they are called

Use const as often as possible to inform the reader (and compiler) that the value being passed as a variable, pointer, function parameter, or member function will not be modified or mutated in any way.


const Variables

Below we have two values, where one has the const qualifier and the other does not.

int Foo = 5; // non-const
const int Bar = 22; // const

From this declaration alone, we know (as does the compiler) that Foo can be modified, but Bar is meant to be a read-only value.

If we attempted to reassign the value of Foo, the compiler would allow it:

Foo = 8; // allowed

But if we attempted to reassign the value of Bar, the compiler would complain that the value can't be reassigned because it is read-only.

Bar = 32; // error, can not mutate a read-only value

This practice helps to document to anyone reading the code the programmer's intent behind the use of the variable.


const Function Parameters

We can also qualify function parameters as being const, telling us (and the compiler) which values are mutable and which are immutable.

The function below takes 3 parameters, with two marked as const.

void ModifyValues(string NewValX, const int NewValY, const float NewValZ)
{
    NewValX = "new string value"; // allowed
    NewValY = 10; // error, can not mutate a read-only value
    NewValZ = 3.4f; // error, can not mutate a read-only value
}

The function scope does not allow ValY or ValZ to be mutated because of the const qualifier, no matter the values passed in.

This strict enforcement also applies when a non-const value is passed into a const qualified function parameter.

string ValX = "original string value"; // non-const
int ValY = 5; // non-const
const float ValZ = 1.0f; // const

void ModifyValues(string NewValX, const int NewValY, const float NewValZ)
{
    NewValX = "new string value"; // allowed
    NewValY = 10; // error; can not mutate a read-only value
    NewValZ = 3.4f; // error, can not mutate a read-only value
}

In the example above, although int ValY = 5; is a non-const variable, the const qualifier in the ModifyValues() function prevents the value within the function scope from being mutated.


const Member Functions

We can also qualify member functions as const which guarantees that the function will not mutate the state of the object (this) when called.

void ModifyValues() {} // non-const member function
void GetValues() const {}  // const member function

When a member function is qualified as const, this does mean the const member function is not allowed to call a non-const member function.

void ModifyValues() {} // non-const member function
void TryToGetCurrentValues() const {}

void GetValues() const // const member function
{
    ModifyValues(); // error, const function can not call non-const function
    TryToGetCurrentValues(); // allowed
}