22

This question is inspired by a question about final in java.

In C/C++, should I use const whenever possible?

I know there is already a related question about using const in parameters. Unfortunately that question and it's answers don't fully answer my question, because it's only about function parameters, but I would also like to know about other cases (eg: local variables).

Also, almost all answers to that question say we should use const because it contains useful information about the accessibility of variables. But this seems to conflict with an answer about using final in Java which states final may be superfluous if it doesn't contain extra information and so it should be omitted to keep the code short and clean.

So, should I use const whenever possible? If so, why is the advice for const in C++ different from the advice for final in Java?

ocomfd
  • 5,652
  • 8
  • 29
  • 37

5 Answers5

24

First of all, since you referenced Java's final, that is a totally different beast than const. Final means the reference cannot change, but says nothing about mutability. Const goes further by saying "a const reference cannot mutate" which is a much stronger guarantee. To do this in Java, internal state must be final and determined at construction time. Const is a lot easier to use, and an existing object can be "promoted" into a const reference.

Yes, you should use const whenever possible. It makes a contract that your code will not change something. Remember, a non-const variable can be passed in to a function that accepts a const parameter. You can always add const, but not take it away (not without a const cast which is a really bad idea).

Const-correctness may be tedious at times, but it helps guarantee immutability. This is crucial in multi-threaded code where threads share objects. It makes certain tasks more efficient: instead of copying state, just reuse the same immutable object. Libraries might accept const parameters in order to provide a guarantee to the programmer that no, your object will not change in an unpredictable way in the black hole that is the library's guts.

  • 1
    Up vote because you explain that `final` and `const` do not have the same guarantees. – Bill Door Oct 05 '16 at 04:31
  • 3
    Constness is about writeability, not about mutability. – Basilevs Oct 05 '16 at 09:45
  • @Basilevs what happens if you write to an object? It mutates. How do you mutate an object? Write to it. –  Oct 05 '16 at 14:04
  • 5
    What happens if you write to a const reference? A compile time error. What happens if you write to the object that is referenced somewhere by const reference via another non-const reference? It mutates. Immutable object can't mutate, hence const refernce does not necessarily reference immutable object. – Basilevs Oct 05 '16 at 15:45
  • 1
    @Basilevs your observation only applies with const refs. If an object itself is declared const (not just the reference) then it it is more-or-less immutable (unless someone nefariously casts away the constness). – Matthew James Briggs Nov 08 '16 at 05:36
  • My knowledge is a bit outdated, how do you declare an object (not type) to be const? – Basilevs Nov 08 '16 at 05:40
  • @Basilevs an _object_ cannot be const, only a reference or pointer to an object. Maybe the other poster was referring to an object containing only const internal state, i.e. immutable? –  Nov 09 '16 at 01:12
  • @Snowman an object can **very definitely** be const. `const int i = 1;` is an object that is neither a reference nor a pointer, and it is const – Caleth Aug 30 '17 at 08:41
8

Personally, const takes me very little time to write, and very little time to read, usually much less than it takes to check whether any code mutates the variable, and it actually prevents me from writing bugs (anyone ever incremented their end iterator by accident? Etc)

I also find that being strict about const usage guides me towards better code in other ways, like creating helper functions to do non-trivial initialization.

Bwmat
  • 769
  • 1
  • 6
  • 14
6

I'm going to disagree with the other posters and recommend you don't use top-level const on local variables and parameters. (References and pointers to const, i.e. const T&, are different, and you should use them for correctness at all times when it's appropriate.)

The advantages of top-level const are:

  • Makes it clear that the local variables are not meant to be mutated.
  • Gives a compiler error if you accidentally do attempt to mutate them.

The disadvantages are:

  • Visual clutter.
  • Cannot be used on "pseudo-const" variables, i.e. variables that are initialized in some manner more complicated than direct construction, but not modified after, e.g. using getline:

    std::string line; // cannot be const
    std::getline(std::cin, line);
    // line should be const from here on out
    
  • Prevents move-out optimization on function call and return:

    std::string f1();
    std::string f2(std::string s);
    std::string f3() {
      const std::string s = f1(); // s is not meant to be modified
      // but I still want the move optimization here:
      const std::string result = f2(std::move(s)); // this doesn't move
      // and I want the compiler to move out here:
      return result; // this will probably RVO, but if not, the move
                     // constructor will not be used due to the const
    }
    

I have worked on a codebase where local const was used a lot, and I found it not helpful at all, yet it filled the code with subtle pessimizations as above. I personally prefer to adopt a general policy of modifying variables as rarely as possible, and making functions small enough that the usage of a variable is obvious, and even if it is modified, the complexity of the function is low enough to make it a non-issue.

Sebastian Redl
  • 14,950
  • 7
  • 54
  • 51
  • 2
    Your point about move-from is showing where you are not using the local in a const manner, as you (intend to) modify it with the move – Caleth Oct 25 '16 at 11:54
  • 1
    @Caleth No, that's the point. I don't intend to modify it. I just want to pass the value, or return it, and I want it to be efficient. Conceptually, the modification is just an optimization, which is not meant to be observable (since the variables aren't used afterwards). Practically, yes, there's a modification, since C++ doesn't have true destructive moves (like Rust has). That's exactly why I don't want `const` on locals: because it prevents technical modifications, not just conceptual modifications. – Sebastian Redl Oct 25 '16 at 13:11
  • 2
    You don't want to modify the *value*, but you do want to modify the *variable*. You can instead use const& instead, and modify neither – Caleth Oct 25 '16 at 13:57
  • Your pseudo-const can be rewritten using an immediately-invoked lambda: `const auto line = [&]{ std::string r; std::getline(std::cin, r); return r; }();` The technique is generally applicable even beyond this, but a bit more convoluted than the original. Still, better than a comment, and the extra enforcement by the compiler might be ample compensation. – Deduplicator Sep 16 '21 at 16:55
4

The const keyword should be used for local variables, just like parameters. It's useful because:

  • Easier to read the code. When someone reads the variable declaration, she knows it won't change. One less thing to worry while reading your code.
  • Prevent you accidentally modify the variable
  • No runtime penalty, everything is checked statically. It's like a free lunch, const should take just a second to write, so it's no big deal.
  • It's always a good idea to make your variables/parameters in your multi-threaded applications. Even your application is not multi-threaded, it's still a good habit.
  • You give an opportunity for your C++ compiler to optimize your code.

Note that there's no right/wrong answer here. In your link, the answerer who had the most upvotes argued final shouldn't be used locally. However, the next answerer strongly recommended it.

If your function is simple and trivial, you shouldn't add const because everyone understands your intention. However, if the logic in your function is non-trivial, you should use the keyword. Remember, there is little to lose.

ABCD
  • 1,166
  • 1
  • 8
  • 13
2

For what it's worth, the Google C++ Style Guide says,

Using const on local variables is neither encouraged nor discouraged.

dshin
  • 121
  • 1
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-ask). – Community Sep 16 '21 at 15:38
  • 1
    I think it’s quite clear. Google says: Do whatever you prefer. – gnasher729 Sep 18 '21 at 16:50
  • Does anyone know the reason, why Google neither encourages nor discourages? Why not to say: "mark local variables as const whenever you can"? – mercury0114 Jan 27 '23 at 08:47
  • There is a cost/benefit tradeoff to adding `const`. The cost is that it adds more characters to the code. Google essentially abstained from making a judgment on this tradeoff. – dshin Jan 27 '23 at 21:14