6

I do that. Even with value-type function parameters and local variables. Seems like a good idea. However, my team's leader calls it 'const spam'. He is against declaring primitive types and such as const. Even if they should be. I'm just thinking how hard should I try to convince him that const is good.

phuclv
  • 37,963
  • 15
  • 156
  • 475
NFRCR
  • 5,304
  • 6
  • 32
  • 37
  • 1
    Even a good thing like `const` can be taken too far. – Beta Apr 11 '13 at 13:27
  • Some style guides state that arguments passed into functions should be `const` and copied to a local variable. This makes it clear that the passed in value should not be modified. It also makes it clear that the object will not be modified if you declare it const, so I don't see how it is const spam. –  Apr 11 '13 at 13:27
  • 2
    const IS good, but I agree with your team leader that for arguments sent by value it is overkill. – Zdeslav Vojkovic Apr 11 '13 at 13:27
  • Have a look (or tell them to look at) [this](http://stackoverflow.com/questions/467899/advantages-of-const-in-c), [this](http://stackoverflow.com/questions/455518/how-many-and-which-are-the-uses-of-const-in-c), and/or [this](http://www.parashift.com/c++-faq-lite/const-correctness.html). – JBentley Apr 11 '13 at 13:28
  • 3
    (value-) const on function parameters is a bit wobbly, as it doesn't change the function signature -- i.e. `void f(const int);` and `void f(int);` is the same signature as far as the compiler is concerned. – Martin Ba Apr 11 '13 at 13:29
  • I've recently watched a [talk by Herb Sutter](http://herbsutter.com/2013/01/01/video-you-dont-know-const-and-mutable/), in which he states that `const` in the C++11 Std Lib means _thread-safe_. Maybe that could be a reason not to use `const` everywhere? I'd use it for POD, too (because they should be bit-wise `const` if they're `const`, and therefore thread-safe). – dyp Apr 11 '13 at 13:32
  • @DyP, it is thread-safe in sense that it can't be changed if shared between threads. if you create a copy (i.e. pass by value), you share nothing, so it is also thread safe – Zdeslav Vojkovic Apr 11 '13 at 13:40
  • @ZdeslavVojkovic True, and if passed by `const&`, would you have to use some sort of atomic access (e.g. on `uint64_t` on x86 architectures)? – dyp Apr 11 '13 at 13:43
  • @DyP, if it is `const&` in both threads then not as state is not changed, otherwise you would. const just means that compiler will not allow you to change the target, it doesn't cover atomicity. – Zdeslav Vojkovic Apr 11 '13 at 13:55
  • http://www.gotw.ca/publications/advice98.htm - "Don't shoot yourself (or your fellow programmers!) in the foot. Always check your safety latch: Be const-correct. Write const whenever possible, and smile at the thought of cleaner, safer, tighter code." – Quokka Aug 08 '22 at 22:42

2 Answers2

16

Very hard. He is wrong. C++ should have been designed with const the default in the first place, and there is nothing wrong with applying const generously. It is a good thing (unlike your team's leader).

For example:

void foo()
{
    const int x = some_function();
    // ^ Now this can't be changed. Good.

    // do stuff with `x`
}

Similarly:

void foo(const int x) // <-- x can't be changed. Good.
{
   // do stuff with `x`
}

void bar()
{
   foo(5);
}

What you don't need to do is accept objects of built-in types by const reference, as that is just kind of pointless.

(And, of course, sometimes you want to be able to change the value of some object. In those scenarios, obviously, don't use const.)

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • I've even heard once using `const&` everywhere was premature optimization. But are there any disadvantages (on PODs/built-in types)? Couldn't you use it as a general rule? – dyp Apr 11 '13 at 13:33
  • 1
    I would argue that `void foo(const int x)` breaks encapsulation by leaking the function implementation details into signature. From the outside `void foo(int x)` is equally clear in conveying the message that the original argument will be intact as it is passed by value. This leaves us with making clearer that `foo` implementation will not change its own copy of the argument. Callee doesn't care about it at all, but if you change the implementation later on and remove constness, you need to rebuild all dependent compilation units, just because you have changed a function implementation detail. – Zdeslav Vojkovic Apr 11 '13 at 13:38
  • 3
    @ZdeslavVojkovic actually, you don't need to change anything, since `void foo(int)` and `void foo(const int)` are the same signature. Which points to other problems: your header *could* say `const int`, and your implementation not. – juanchopanza Apr 11 '13 at 13:44
  • @juanchopanza: On the other hand, this inconsistency doesn't hurt. Everything is fine as long as you avoid top-level `const` qualifications in your function declarations / headers - just as a guideline. That is not relevant to clients, so implementation details should be omitted. Then, the implementation would be free to add or remove top-level `const` qualifications. – Andy Prowl Apr 11 '13 at 13:50
  • @juanchopanza, sure, but I assumed the same sig in header and impl, having them different is more confusing, IMO. – Zdeslav Vojkovic Apr 11 '13 at 14:00
  • @ZdeslavVojkovic I agree completely, which is why I think it is a bad idea to have the top level consts in function declarations. On the other hand, I think I buy Andy Prowl's argument about the definitions: as an implementation detail, you could have top level const parameters. – juanchopanza Apr 11 '13 at 14:02
4

It certainly doesn't hurt anything and it sends a clear signal to people reading the code later that this variable 'does not change', that's very important to know when modifying code.

  • 1
    it hurts encapsulation and thus maintainability by leaking the function implementation details into signature (IMO, of course, this is a great topic for religious wars :) – Zdeslav Vojkovic Apr 11 '13 at 13:42
  • If it's an argument passed by reference I would argue that it's an implementation detail relevant to the caller. That is to say: what if the caller wanted to pass the same reference to another thread to read from it in parallel? If the caller knows that that reference won't be re-assigned by the callee to something else, they can know it's thread-safe to read from it on the other thread during that method's execution. – Matt Arnold Dec 07 '20 at 14:58