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 someT
(a type, likeint
, orstd::unordered_map<int, int>
), it is making theT
constant. This means theT
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:
- https://mariusbancila.ro/blog/2018/11/23/join-the-east-const-revolution/
- https://stackoverflow.com/questions/1143262/what-is-the-difference-between-const-int-const-int-const-and-int-const
- https://hackingcpp.com/cpp/design/east_vs_west_const.html
- https://stackoverflow.com/questions/3694630/c-const-reference-before-vs-after-type-specifier
- https://stackoverflow.com/questions/2640446/why-do-some-people-prefer-t-const-over-const-t