logo

C++ - const

const keyword declares an object as constant, i.e. once initialized, the value won't change.

Read-only, but not Immutable or always the same

A const object is read-only but this does not imply that it is immutable nor does it imply that the value is always the same.

void f(const std::string& s) {
  const int size = s.size();
  // ...
}

f("");     // size = 0
f("foo");  // size = 3

Other ways to change a const: mutable keyword and const_cast.

What does const apply to?

TL;DR: const applies to the thing left of it, if there's nothing on the left, then it applies to the thing right of it

  • const int*: nothing on the left, so const is for int: a pointer to a constant integer. equivalent to int const *.
  • int* const: a constant pointer to an integer, the pointer cannot point to other address, the content can be changed.
  • const int* const: a constant pointer to a constant integer, both content and the address are read-only, equivalent to int const* const.
  • int const* const*: a pointer to a const pointer to a constant integer.
  • int const* const* const: a constant pointer to a constnat pointer to a constant integer.

Where to use const?

const object

const int kMax = 100;
  • needs to be initialized at the time of declaration.
  • attempt to change the data member of const objects results in a compile-time error.

const member function

class Foo {
  // ...
  int get_data() const;
}

const member function: not allowed to modify the object.

Compare:

  • const function: can be called on any type of object.
  • Non-const function: can only be called by non-const objects.

Note that const means the function does not modify the states of this object, not "read only", for example if a function writes to a database and it does not change the states, it can be const.

class Foo {
  // ...
  absl::Status InsertOrUpdateBarTable() const {
    // ... does not change state of Foo.
  }
}

Function parameters

The const in front of the function parameter indicates that it does not intend to change the states in foo:

void f(const Foo& foo) {
  // ...
}

Best Practices

Prefer const member functions

Make as many functions const as possible so that accidental changes to objects are avoided.

Top-level const

Top-level const on function parameters in declarations that are not definitions is meaningless and ignored by the compiler.

There's very little point in returning a value with top-level const in C++. It's the callers responsibility to decide if they want to mutate the value they obtain from the function or not.

void F(const int x);          // 1: declares F(int)
void F(int* const x);         // 2: declares F(int*)
void F(const int* const x);   // 3: declares F(const int*)

Avoid returning const values

Returning const for values (not references) disables a lot of optimisations and usually causes unnecessary copies. When returning values from functions, avoid marking the type const. (That is, no const T, although const T& and const T* are perfectly fine.)