161

So why exactly is it that it's always recommended to use const as often as possible? It seems to me that using const can be more of a pain than a help in C++. But then again, I'm coming at this from the python perspective: if you don't want something to be changed, don't change it. So with that said, here are a few questions:

  1. It seems like every time I mark something as const, I get an error and have to change some other function somewhere to be const too. Then this causes me to have to change another function somewhere else. Is this something that just gets easier with experience?

  2. Are the benefits of using const really enough to compensate for the trouble? If you don't intend to change an object, why not just not write code that changes it?

I should note that at this point in time, I'm most focused on the benefits of using const for correctness and maintainability purposes, although it is also nice to have an idea of the performance implications.

Dr. Gut
  • 2,053
  • 7
  • 26
Jason Baker
  • 192,085
  • 135
  • 376
  • 510
  • 2
    8yr old retrospective, but.. How about speeding up your code 100x (seen this live)? – lorro Jul 29 '16 at 10:07
  • 2
    I use python a lot and the lack of const has always bothered me. https://stackoverflow.com/questions/2682745/how-do-i-create-a-constant-in-python Using const makes it easier for the programmer and compiler to reason about code safely – qwr Aug 20 '22 at 16:40

16 Answers16

184

This is the definitive article on "const correctness": https://isocpp.org/wiki/faq/const-correctness.

In a nutshell, using const is good practice because...

  1. It protects you from accidentally changing variables that aren't intended be changed,

  2. It protects you from making accidental variable assignments. For instance, you are protected from

    if( x = y ) // whoops, meant if( x == y ).
    
  3. The compiler can optimize it.

At the same time, the compiler can generate more efficient code because it knows exactly what the state of the variable/function will be at all times. If you are writing tight C++ code, this is good.

You are correct in that it can be difficult to use const-correctness consistently, but the end code is more concise and safer to program with. When you do a lot of C++ development, the benefits of this quickly manifest.

SKPS
  • 5,433
  • 5
  • 29
  • 63
Jordan Parmer
  • 36,042
  • 30
  • 97
  • 119
  • I always assumed that const values could be freely cached and thus avoid many concurrency issues or improve speed. Is that true? – Phil H Sep 26 '13 at 21:26
  • 5
    Sure. `const` variables *can* improve speed in the sense that the compiler can generate more optimal code because it knows the full intent and use of the variable. Will you notice the difference? Well, that is debatable upon your application. As far as concurrency is concerned, const-variables are read-only which means there isn't a need for exclusive locks on those variables since the value will always be the same. – Jordan Parmer Sep 26 '13 at 22:21
  • 4
    As of C++11 the standard library also assumes `const` to mean thread-safe and treating your own code this way makes it easier to check for possible multi-threading problems and is an easy way to provide API guarantees for your API users. – pmr Mar 25 '14 at 20:44
  • 4
    For me, one of the biggest value-adds of const correctness is that you know just by looking at function prototypes when pointers are referencing data that is never mutated by the function (i.e. input only). – cp.engr Jan 27 '17 at 17:03
  • 1
    Don't forget that there is _logical_ and _physical_ constness. Any aggregate object contained which is marked as mutable can change, though marking it as such implies that it doesn't have anything to do with the logical constness of the containing object. – Adrian Mar 19 '18 at 21:32
  • @pmr: _"As of C++11 the standard library also assumes const to mean thread-safe"_ Eh? – Lightness Races in Orbit May 31 '19 at 14:22
  • Isn't there a mistake there? Shouldn't the accidental assignment in the `if`statement be under point 2? I mean it's more of protection against accidental assignment than optimization. Also point 2 seem to be a special case of 1 since assignment implies changing the variable. – skyking Jul 15 '22 at 12:14
143

Here's a piece of code with a common error that const correctness can protect you against:

void foo(const int DEFCON)
{
   if (DEFCON = 1)     //< FLAGGED AS COMPILER ERROR! WORLD SAVED!
   {
       fire_missiles();
   }
}
Doug T.
  • 64,223
  • 27
  • 138
  • 202
  • 40
    Of course, most modern compilers warn about assignments in conditionals and we all turn on the treat warnings as errors flag, right :-> – Jack Bolding Sep 26 '08 at 01:06
  • Of course, since foo gets it's own private copy of DEFCON to work with, the real DEFCON value would be unchanged anyway. – Eclipse Sep 26 '08 at 01:28
  • 10
    Don't be too hard on that example: This is the same example evangelized by some developers to convince us to use if(0 ==i) instead of if(i == 0). At last, Doug's pattern of code can be used outside the "if" statement. What's important is it shows one of the benefits of const in a humorous way. + 1. – paercebal Oct 11 '08 at 20:45
  • 2
    Some compilers (and lints) have been warning about this for a long time, and that is much more useful to catch this typo than const: http://codepad.org/Nnf5JUXV. –  Mar 16 '10 at 05:14
  • 9
    @Roger you assume that we live in a world where builds are clean and warning free. My experience is that in a lot of code warnings get lost in the noise. Also, there is a lot of code that does assignments in the if expression and many will argue that it is a valid, "good" style. – Doug T. Mar 16 '10 at 15:51
  • 2
    @Doug: This is not about style, as I use this pattern myself: you can make it obvious with `if ((a = b))`, which also makes it more readable. I won't open the debate about compiler warnings here, but I will point out that various lint tools are more configurable (so no noise), don't require you to change your compiler, and a complete solution to the problem of ==/= typos, while using const only catches some of them. –  Mar 17 '10 at 01:37
  • @WarrenDew : `You don't use if(0 == i)? It has saved me more than once` : My experience with that `if(0 == i)` pattern is that it always been advocated by the same people who refused to use const or any other C++ facility to detect errors at compile time for some reason (e.g. "it's ugly", "it's not C", "I don't like it", "namespaces hurt performance", etc.). I must be a bit biased, but now, when someone tries to sell me that `if(0 == i)` pattern, my first question is: "Do you use const whenever possible?" and if the answer is not a resounding *YES*, then that person's viewpoint is irrelevant. – paercebal Mar 26 '14 at 14:44
72

It seems like every time I mark something as const, I get an error and have to change some other function somewhere to be const too. Then this causes me to have to change another function somewhere else. Is this something that just gets easier with experience?

From experience, this is a total myth. It happens when non const-correct sits with const-correct code, sure. If you design const-correct from the start, this should NEVER be an issue. If you make something const, and then something else doesn't complile, the compiler is telling you something extremely important, and you should take the time to fix it properly.

Chris Mayer
  • 2,316
  • 3
  • 18
  • 14
  • 9
    This has helped me prevent so many bugs where I had a const function about to call a non-const function because I forgot it modifies data underneath. – Mooing Duck Aug 19 '13 at 20:11
  • 13
    Very few people always get to start with clean code bases. Most coding is maintenance on legacy code, where the quoted comment is quite accurate. I use const when writing new leaf functions, but I question whether it's worth chasing things through half a dozen or a dozen call levels of unfamiliar code. – Warren Dew Mar 26 '14 at 02:06
  • 3
    This is completely wrong in my experience. Nested point types creates the biggest headache for this sort of thing, where you can have multiple const-quantifiers in a single type. – Noldorin May 23 '15 at 00:58
  • 4
    "If you design const-correct from the start," how many times you actually have the luxury of forcing const-correctness from the start?? Most of us have to deal with numerous APIs and libraries on a daily bases where this is not the case and there is little you can do about those. So I agree with the OPs sentiment "It seems like every time I mark something as const I get an error a"... – nyholku Mar 28 '19 at 14:42
  • @WarrenDew That's a transitive argument; if the original authors had used `const` properly (i.e. "from the start") then indeed there would not be a problem, which is exactly the point! – Lightness Races in Orbit May 31 '19 at 14:23
39

If you use const rigorously, you'd be surprised how few real variables there are in most functions. Often no more than a loop counter. If your code is reaching that point, you get a warm feeling inside...validation by compilation...the realm of functional programming is nearby...you can almost touch it now...

QBziZ
  • 3,170
  • 23
  • 24
33

It's not for you when you are writing the code initially. It's for someone else (or you a few months later) who is looking at the method declaration inside the class or interface to see what it does. Not modifying an object is a significant piece of information to glean from that.

Antonio Haley
  • 4,702
  • 1
  • 27
  • 19
  • 1
    This is only kind of true. Const is used as protection as well to enforce in-variables through interfaces and so forth. – Jordan Parmer Sep 25 '08 at 23:41
  • It is, but you can enforce that through disciplined coding practices, and the poster states. The real benefit comes from the this being reflected in the API. – Antonio Haley Sep 25 '08 at 23:46
  • 2
    Exactly. It's better to have "const int Value = 5 ;" than have "int ConstValue = 5 ;". +1. – paercebal Oct 11 '08 at 20:48
  • 6
    The right time to put const-correctness in is when you write the API initially. Otherwise you'll get into trouble with const-poisoning when you retrofit it (which is why adding it to old code is a *completely different matter* to doing it in new code). – Donal Fellows Aug 29 '10 at 16:23
  • @DonalFellows this isn't saying put in const later. It is saying that you *get the benefits* later, when you read the code with const already present – Caleth Apr 02 '19 at 08:15
26

Programming C++ without const is like driving without the safety belt on.

It's a pain to put the safety belt on each time you step in the car, and 364 out of 365 days you'll arrive safely.

The only difference is that when you get in trouble with your car you'll feel it immediately, whereas with programming without const you may have to search for two weeks what caused that crash only to find out that you inadvertently messed up a function argument that you passed by non-const reference for efficiency.

andreas buykx
  • 12,608
  • 10
  • 62
  • 76
24

const is a promise your are making as a developer, and enlisting the compiler's help in enforcing.

My reasons for being const-correct:

  • It communicates to clients of your function that your will not change the variable or object
  • Accepting arguments by const reference gives you the efficiency of passing by reference with the safety of passing by value.
  • Writing your interfaces as const correct will enable clients to use them. If you write your interface to take in non-const references, clients who are using const will need to cast constness away in order to work with you. This is especially annoying if your interface accepts non-const char*'s, and your clients are using std::strings, since you can only get a const char* from them.
  • Using const will enlist the compiler in keeping you honest so you don't mistakenly change something that shouldn't change.
JohnMcG
  • 8,709
  • 6
  • 42
  • 49
22

My philosophy is that if you're going to use a nit-picky language with compile time checks than make the best use of it you can. const is a compiler enforced way of communicating what you mean... it's better than comments or doxygen will ever be. You're paying the price, why not derive the value?

Pat Notz
  • 208,672
  • 30
  • 90
  • 92
20

For embedded programming, using const judiciously when declaring global data structures can save a lot of RAM by causing the constant data to be located in ROM or flash without copying to RAM at boot time.

In everyday programming, using const carefully helps you avoid writing programs that crash or behave unpredictably because they attempt to modify string literals and other constant global data.

When working with other programmers on large projects, using const properly helps prevent the other programmers from throttling you.

bk1e
  • 23,871
  • 6
  • 54
  • 65
15

const correctness is one of those things that really needs to be in place from the beginning. As you've found, its a big pain to add it on later, especially when there is a lot of dependency between the new functions you are adding and old non-const-correct functions that already exist.

In a lot of the code that I write, its really been worth the effort because we tend to use composition a lot:

class A { ... }
class B { A m_a; const A& getA() const { return m_a; } };

If we did not have const-correctness, then you would have to resort to returning complex objects by value in order to assure yourself that nobody was manipulating class B's internal state behind your back.

In short, const-correctness is a defensive programming mechanism to save yourself from pain down the road.

Peter Kovacs
  • 2,657
  • 21
  • 19
14

const helps you isolate code that "change things" behind your back. So, in a class, you'd mark all methods that don't change the state of the object as const. This means that const instances of that class will no longer be able to call any non-const methods. This way, you're prevented from accidentally calling functionality that can change your object.

Also, const is part of the overload mechanism, so you can have two methods with identical signatures, but one with const and one without. The one with const is called for const references, and the other one is called for non-const references.

Example:

#include <iostream>

class HelloWorld {
    bool hw_called;

public:
    HelloWorld() : hw_called(false) {}

    void hw() const {
        std::cout << "Hello, world! (const)\n";
        // hw_called = true;  <-- not allowed
    }

    void hw() {
        std::cout << "Hello, world! (non-const)\n";
        hw_called = true;
    }
};

int
main()
{
    HelloWorld hw;
    HelloWorld* phw1(&hw);
    HelloWorld const* phw2(&hw);

    hw.hw();    // calls non-const version
    phw1->hw(); // calls non-const version
    phw2->hw(); // calls const version
    return 0;
}
C. K. Young
  • 219,335
  • 46
  • 382
  • 435
8

Say you have a variable in Python. You know you aren't supposed to modify it. What if you accidentally do?

C++ gives you a way to protect yourself from accidentally doing something you weren't supposed to be able to do in the first place. Technically you can get around it anyways, but you have to put in extra work to shoot yourself.

Greg Rogers
  • 35,641
  • 17
  • 67
  • 94
5

There is a nice article here about const in c++. Its a pretty straight forward opinion but hope it helps some.

Ólafur Waage
  • 68,817
  • 22
  • 142
  • 198
3

When you use the "const" keyword, you're specifying another interface to your classes. There is an interface that includes all methods, and an interface that includes only the const methods. Obviously this lets you restrict access to some things that you don't want changed.

Yes, it does get easier with time.

Wesley Tarle
  • 658
  • 3
  • 6
2

I like const correctness ... in theory. By every time I have tried to apply it rigourously in practice it has broken down eventually and const_cast starts to creep in making the code ugly.

Maybe it is just the design patterns I use, but const always ends up being too broad a brush.

For example, imagine a simple database engine ... it has schema objects, tables, fields etc. A user may have a 'const Table' pointer meaning that they are not allowed to modify the table schema itself ... but what about manipulating the data associated with the table? If the Insert() method is marked const then internally it has to cast the const-ness away to actually manipulate the database. If it isn't marked const then it doesn't protect against calling the AddField method.

Maybe the answer is to split the class up based on the const-ness requirements, but that tends to complicate the design more than I would like for the benefit it brings.

Rob Walker
  • 46,588
  • 15
  • 99
  • 136
  • I think your example is a case of overusing const, but don't forget about the mutable modifier, which can be applied to instance variables to remove the const-ness. – Zooba Sep 26 '08 at 02:12
  • 2
    When would an Insert() function ever be marked const unless its misnamed? Adding things usually modifies the thing you added it to, meaning it isn't const. What you really wanted was a TableWithConstSchema. – Greg Rogers Sep 26 '08 at 03:39
  • I could add another class, but I don't want to make the API unnecessarily complex purely for the sake of const-correctness. – Rob Walker Sep 26 '08 at 16:05
1

You can give the compiler hints with const as well....as per the following code

#include <string>

void f(const std::string& s)
{

}
void x( std::string& x)
{
}
void main()
{
    f("blah");
    x("blah");   // won't compile...
}
Keith Nicholas
  • 43,549
  • 15
  • 93
  • 156