29
votes

In the following C++ functions:

void MyFunction(int age, House &purchased_house)
{
    ...
}


void MyFunction(const int age, House &purchased_house)
{
    ...
}

Which is better?

In both, 'age' is passed by value. I am wondering if the 'const' keyword is necessary: It seems redundant to me, but also helpful (as an extra indication the variable will not be changing).

Does anyone have any opinion as to which (if any) of the above are better?

12
A similar question was in this StackOverflow post: stackoverflow.com/questions/117293/…Void

12 Answers

26
votes

This, IMHO, is overusing. When you say 'const int age,...' what you actually say is "you can't change even the local copy inside your function". What you do is actually make the programmer code less readable by forcing him to use another local copy when he wants to change age/pass it by non-const reference.

Any programmer should be familiar with the difference between pass by reference and pass by value just as any programmer should understand 'const'.

67
votes

First, it's just an implementation detail, and if you put const there, don't put it in the declaration set (header). Only put it in the implementation file:

// header
void MyFunction(int age, House &purchased_house);

// .cpp file
void MyFunction(const int age, House &purchased_house);
{
    ...
}

Whether or not a parameter is const in a definition is purely an implementation detail, and should not be part of the interface.

I've not seen this sort of thing often, and i also don't do this. Having the parameter const would confuse me more often than help, because i would immediately pattern-match-fail it to "const int &age" :) The matter of course is entirely different from having const at another level:

// const is a *good* thing here, and should not be removed,
// and it is part of the interface
void MyFunction(const string &name, House &purchased_house);
{
    ...
}

In this case, the const will affect whether the function can change the caller's argument. Const in this meaning should be used as often as possible, because it can help ensuring program correctness and improve self-documenting the code.

45
votes

I recommend reading Herb Sutter. Exceptional C++. There is a chapter "Const-Correctness".

"In fact, to the compiler, the function signature is the same whether you include this const in front of a value parameter or not."

It means that this signature

void print(int number);

is effectively the same as this:

void print(int const number);

So, to the compiler there is no difference how you declare a function. And you can't overload it by putting the const keyword in front of a pass by value parameter.

Read further, what Herb Sutter recommends:

"Avoid const pass-by-value parameters in function declarations. Still make the parameter const in the same function's definition if it won't be modified."

He recommends to avoid this:

void print(int const number);

Because that const is confusing, verbose and redundant.

But in the definition, you should do that (if you won't change the parameter):

void print(int const number)
{
   // I don't want to change the number accidentally here
   ...
}

So, you'll be sure that even after 1000 lines of function's body you always have the number untouched. The compiler will prohibit you from passing the number as a non-const reference to another function.

9
votes

You not only indicate that it will not change, it will prevent your code from thinking it can and it will be caught at compilation time.

8
votes

See Meyers and 'Effective C++' on this, and do use const liberally, especially with pass-by-reference semantics.

In this case of atomic variables, efficiency does not matter but code clarity still benefits.

7
votes

Well, as other have already said, from the point of view of C++ language, the above const has no effect on function signature, i.e. the function type remains the same regardless of whether the const is there or not. The only effect it has at the level of abstract C++ language is that you can't modify this parameter inside the function body.

However, at the lower level, the const modifier applied to the parameter value can have some optimization benefits, given a sufficiently clever compiler. Consider two functions with the same parameter set (for simplicity)

int foo(const int a, const double b, const long c) {
   /* whatever */
}

void bar(const int a, const double b, const long c) {
   /* whatever */
}

Let's say somewhere in the code they are called as follows

foo(x, d, m);
bar(x, d, m);

Normally, compilers prepare stack frame with arguments before they call a function. In this case the stack will usually be prepared twice: once for each call. But a clever compiler might realize that since these functions do not change their local parameter values (declared with const), the argument set prepared for the first call can be safely reused for the second call. Thus it can prepare the stack only once.

This is a rather rare and obscure optimization, which can only work when the definition of the function is known at the point of the call (either same translation unit, or an advanced globally-optimizing compiler), but sometimes it might be worth mentioning.

It is not correct to say that it is "worthless" or "has no effect", even though with a typical compiler this might be the case.

Another consideration that is worth mentioning is of different nature. There are coding standards out there, which require coders not to change the initial parameter values, as in "don't use parameters as ordinary local variables, parameter values should remain unchanged throughout the function". This kinda makes sense, since sometimes it makes it easier to determine what parameter values the function was originally given (while in debugger, inside the body of the function). To help enforce this coding standard, people might use const specifiers on parameter values. Whether it is worth it or not is a different question...

4
votes

One benefit of using const is that you cannot accidentally change the value of age in the middle of MyFunction (in the event you forgot it was not pass by reference). One "disadvantage" is that you can't recycle age with code like foo.process(++age);.

4
votes

You're correct, the only purpose of "const int age" is that age can not be changed. This can be however very confusing for most of programmers. So if these approach is not used widely in your code, I'd advice to omit const.

4
votes

Second variant is better. In the first one you can accidently change variable age.

4
votes

You should use const on a parameter if (and only if) you would use it on any other local variable that won't be modified:

const int age_last_year = age - YEAR;

It's sometimes handy to mark local variables const where possible, since it means you can look at the declaration and know that's the value, without thinking about intermediate code. You can easily change it in future (and make sure you haven't broken the code in the function, and maybe change the name of the variable if it now represents something slightly different, which is changeable, as opposed to the previous non-changing thing).

As against that, it does make the code more verbose, and in a short function it's almost always very obvious which variables change and which don't.

So, either:

void MyFunction(const int age, House &purchased_house)
{
    const int age_last_year = age - YEAR;
}

or:

void MyFunction(int age, House &purchased_house)
{
    int age_last_year = age - YEAR;
}
4
votes

Here are some great articles and a book I found explaining the advantages of using const:


Can I propose the following maxim to you?

If an object/variable can be qualified has being constant, it should be. At worst, it will not cost anything. At best, you will be documenting the role of the object/variable in your code and it will allow the compiler the opportunity to optimize your code even more.

Some compilers neglect to exploit the potential of optimization with the use of 'const' and that has lead many experts to neglect the use of constant parameters by value when it could be used. This practice takes more strictness, but it will not be harmful. At worst, you do not lose anything , but you do not gain anything too and at best, you win from using this approach.


For those who do not seem to understand the utility of a const in a by value parameter of a function/method... here is a short example that explains why:

.cpp

void WriteSequence(int const *, const int);

int main()
{
    int Array[] = { 2, 3, 4, 10, 12 };
    WriteSequence(Array, 5);
}


#include <iostream>
using std::cout;
using std::endl;
void WriteSequence(int const *Array, const int MAX)
{
    for (int const * i = Array; i != Array + MAX; ++i)
      cout << *i << endl;
}

What would had happen if I would had removed the const in front of int MAX and I had written MAX + 1 inside like this?

void WriteSequence(int Array[], int MAX)
{
    MAX += MAX;
    for (int * i = Array; i != Array + MAX; ++i)
      cout << *i << endl;
}

Well your program would crash! Now, why would someone write "MAX += MAX;" ? Perhaps human error, maybe the programmer was not feeling well that day or perhaps the programmer simply did not know how to write C/C++ code. If you would have had const, the code would have not even compiled!

Safe code is good code and it does not cost anything to add "const" when you have it!


Here is an answer from a different post for a very similar question:

"const is pointless when the argument is passed by value since you will not be modifying the caller's object."

Wrong.

It's about self-documenting your code and your assumptions.

If your code has many people working on it and your functions are non-trivial then you should mark "const" any and everything that you can. When writing industrial-strength code, you should always assume that your coworkers are psychopaths trying to get you any way they can (especially since it's often yourself in the future).

Besides, as somebody mentioned earlier, it might help the compiler optimize things a bit (though it's a long shot).

Here is the link: answer.

1
votes

Having a primitive type that is passed by value const is pretty much worthless. Passing a const to a function is generally useful as a contract with the caller that the funciton will not change the value. In this case, because the int is passed by value, the function can't make any changes that will be visible outside the function.

On the other hand, rreferences and non trivial object types should always use const if there is not going to be any changes made to the object. In theory this might allow for some optimization, but the big win is the contract I mentioned above. The downside is of course, that it can make your interface much larger, and const it a tough thing to retrofit into an existing system (or with a 3rd party API not using const everywhere).