Posts C++ East/West const, const T*, const T *const, T const *, and T *const
Post
Cancel

C++ East/West const, const T*, const T *const, T const *, and T *const

Understanding const in C++

Every C++ programmer must’ve at one point struggled with the subtle differences between the following declarations:

1
2
3
4
5
6
7
const T num;
T const num;
T *ptr;
T const *ptr;
T *const ptr;
T const *const ptr;
const T *const ptr;

In the example above, T is just a type placeholder that can be replaced with int, std::string, an STL container, or any custom class you like.

To understand the declarations in the example, we need only understand the one rule of C++’s const qualifier: const applies to what’s immediately on the left. If there’s nothing on the left, apply to its immediate right.”

Let’s break this down further.

  • If the const qualifier is applying to some T (a type, like int, or std::unordered_map<int, int>), it is making the T constant. This means the T is immutable, despite the pointer pointing to it (if there is one) being potentially mutable.

  • If the const qualifier is applying to *, it’s making the pointer itself constant. This means the pointer cannot change the address it points to, yet the value at that address is potentially mutable.

With this in mind, it shouldn’t be hard to decode the declarations above:

1
2
3
4
5
6
7
const T obj;         // obj is a constant T
T const obj;         // obj is a constant T
T *ptr;              // ptr is a mutable pointer to a mutable T
T const *ptr;        // ptr is a mutable pointer to a constant T
T *const ptr;        // ptr is a constant pointer to a mutable T
T const *const ptr;  // ptr is a constant pointer to a constant T
const T *const ptr;  // ptr is a constant pointer to a constant T

What about references (&)?

For references, there is less ambiguity, because we cannot apply the const qualifier to the “reference” itself anyways:

1
2
3
const T &obj = 0;  // obj is a reference to a constant T
T const &obj = 0;  // obj is a reference to a constant T
T &const obj = 0;  // ERROR: Invalid Reference Qualifier Application

East const or West const?

Like tabs vs. spaces and the editor wars (Vi vs. Emacs), East const vs. West const has been a long rivalry in the programmer community (at least for C++ developers), with West const being the conventional standard and East const being the modern revolution bringing arguments such as “more consistent and logical”. To demonstrate the differences, consider the following example:

1
2
3
4
5
const int num = 0;  // West const
int const num = 0;  // East const

const T *const ptr;  // West const
T const *const ptr;  // East const

Personally, I prefer to use West const because I think it reads more intuitive (const int declares a “constant integer”), is more popular in existing code bases, and is the recommended style in C++ Core Guidelines. Additionally,

  • const T & is the style used in Bjarne Stroustrup’s The C++ Programming Language book.
  • const T & is the style used in the C++ standard itself.
  • const T * is the style used in K&R’s The C Programming Language book.
  • const T * is the style used in the C standard.

However, East const does have the advantage of being super consistent, always applying const to its immediate left with no exceptions (I.e. there will always be something on the left to apply to, because const int num would be written as int const num in East const style, for instance.). To read about more arguments for East const, consider this well-written blog post by an East const advocate.

As in all programming style-related debates, just pick one and be consistent with it throughout a project. It also helps to understand different styles so we never get confused regardless of the code base.

That’s all I have this time, thanks for stopping by.

References:

This post is licensed under CC BY 4.0 by the author.