Sell me on const correctness

C++Const Correctness

C++ Problem Overview


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 on changing an object, why not just not write code that doesn't change 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.

C++ Solutions


Solution 1 - C++

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, and

  3. The compiler can optimize it. For instance, you are protected from

    if( x = y ) // whoops, meant if( x == y )
    

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.

Solution 2 - C++

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();
   }
}

Solution 3 - C++

> 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.

Solution 4 - C++

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...

Solution 5 - C++

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.

Solution 6 - C++

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.

Solution 7 - C++

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.

Solution 8 - C++

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?

Solution 9 - C++

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.

Solution 10 - C++

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.

Solution 11 - C++

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;
}

Solution 12 - C++

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.

Solution 13 - C++

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

Solution 14 - C++

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.

Solution 15 - C++

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.

Solution 16 - C++

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...
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJason BakerView Question on Stackoverflow
Solution 1 - C++Jordan ParmerView Answer on Stackoverflow
Solution 2 - C++Doug T.View Answer on Stackoverflow
Solution 3 - C++Chris MayerView Answer on Stackoverflow
Solution 4 - C++QBziZView Answer on Stackoverflow
Solution 5 - C++Antonio HaleyView Answer on Stackoverflow
Solution 6 - C++JohnMcGView Answer on Stackoverflow
Solution 7 - C++andreas buykxView Answer on Stackoverflow
Solution 8 - C++Pat NotzView Answer on Stackoverflow
Solution 9 - C++bk1eView Answer on Stackoverflow
Solution 10 - C++Peter KovacsView Answer on Stackoverflow
Solution 11 - C++Chris Jester-YoungView Answer on Stackoverflow
Solution 12 - C++Greg RogersView Answer on Stackoverflow
Solution 13 - C++Ólafur WaageView Answer on Stackoverflow
Solution 14 - C++Wesley TarleView Answer on Stackoverflow
Solution 15 - C++Rob WalkerView Answer on Stackoverflow
Solution 16 - C++Keith NicholasView Answer on Stackoverflow