Just make everything const
that you can! That's the bare minimum you could do for your compiler!
This is a piece of advice, many senior developers tend to repeat to juniors, while so often even the preaching ones - we - fail to follow this rule.
It's so easy just to declare a variable without making it const
, even though we know that its value should never change. Of course, our compiler doesn't know it.
It's not enough that we fail to comply with our own recommendations, we are also not specific enough. So if others just blindly follow our recommendations without much thinking, then it just messes things up. Compilation failures are easy to spot early on, but dangling references or worse performance due to extra copies are more difficult to identify. Hopefully, those are caught not later than the code review.
But don't be mad at the people following your words blindly. If you share pieces of advice without much thinking if you don't expect critical thinking from yourself, why would you expect more from others?
I digressed, let's get back to our topic. So what kind of const
s are out there?
In this series of articles, we'll discuss about:
-
const
functions -
const
local variables -
const
member variables -
const
return types -
const
parameters
In this post, we are going to explore const functions and const local variables.
Let's get started.
const
functions
You can declare a non-static member function const
if it doesn't change the value of the underlying object. This is recursive in a sense, that it cannot modify any of the members. To guarantee that, it cannot call non-const functions on its members.
#include <iostream>
class A {
public:
void bar() {
// ...
}
};
class B {
public:
void foo() const {
a.bar(); // A::bar() is not const, so this call generates a compilation error!
}
private:
A a{};
};
int main() {
auto b{B{}};
b.foo();
}
On the other hand, we can call non-const functions on locally initialized objects or on function parameters.
In case a function has two overloaded versions where one is const
and the other is not, the compiler will choose which one to call based on whether the object itself is const or not.
The feature of const
functions is something you should use all the time. Making the function const
is meaningful. It helps the compiler to use optimizations and in addition, it clarifies the intent of the author. It shows the reader that if he calls such a function it will not have any effect on the members' state.
Use it without moderation.
const
variables
If you declare a local variable const
, you simply mark it immutable. It should never ever change its value. If you still try to modify it later on, you'll get a compilation error. For global variables, this is rather useful, as otherwise, you have no idea who can modify their value. Of course, you should not use global variables and then you don't face the problem...
Those global const
s can introduce coupling among your classes or even components that you should avoid otherwise. You might even face the static initialization order fiasco, but this a problem for another day...
Otherwise, declaring variables as const
also helps the compiler to perform some optimizations. Unless you explicitly mark a variable const
, the compiler will not know (at least not for sure) that the given variable should not change. Again this is something that we should use whenever it is possible.
In real life, I find that we tend to forget the value making variables const, even though there are good examples at conference talks and it really has no bad effect on your code, on maintainability.
This is such an important idea that in Rust, all your variables are declared as const
, unless you say they should be mutable.
We have no reason not to follow similar practices.
Declare your local variables const
if you don't plan to modify them. Regarding global variables, well, avoid using then, but if you do, also make them const
whenever possible.
Conclusion
Today, we started a new series about when and how to use the const
keyword in C++. In this episode, we learned about const
local/global variables and const
functions. They come for free and even let the compiler to make some optimizations. At the same time, they increase the readability of your code. Use them without moderation.
On the other hand, I've never simply said variables. It's because not the same considerations apply to member variables.
Stay tuned, next time we'll learn about whether having const
member variables is a good idea or not.
Connect deeper
If you found interesting this article, please subscribe to my personal blog and let's connect on Twitter!