15

When learning C++, one of the first functions one gets for learning the concept of a function is something like

int add(int a, int b)
{
    return a+b;
}

Now I was wondering: Should I use the const-keyword here, or rather not, resulting in

int add(const int a, const int b)
{
    return a+b;
}

But would that make sense? Would it speed my program up, do some other important stuff, or just increase confusion?

Mr.C64
  • 41,637
  • 14
  • 86
  • 162
arc_lupus
  • 3,942
  • 5
  • 45
  • 81
  • It would certainly be confusing in the function declaration, where the `const` makes no difference (`void foo(int)` is exactly the same as `void foo(const int);`. But not in the definition. Of course, that is my opinion (hence comment, not answer.) – juanchopanza Oct 04 '16 at 09:25
  • 2
    Possible duplicate of [Use of 'const' for function parameters](http://stackoverflow.com/questions/117293/use-of-const-for-function-parameters) – demonplus Oct 04 '16 at 09:29
  • Voted to close as **primarily opinion based**. I personally use top level `const` qualifiers on arguments, as a single convention applied throughout the code. I find that uniform conventions simplify things. Then you know that there's something special when the convention is not used. But that's a personal preference. – Cheers and hth. - Alf Oct 04 '16 at 09:31
  • 1
    Even more opinion based is that seeing a parameter passed by `const` value helps gauge the competency of a programmer: I have found that useful at times. – Bathsheba Oct 04 '16 at 09:32
  • @Cheersandhth.-Alf Kerrek's option 1 or 2? Personally, I prefer 3 over 2 over 1. – Deduplicator Oct 04 '16 at 09:35
  • @Deduplicator: It would be 2, not used in pure declaration, except that I think header only modules are nice. :) There was once some discussion about that interface versus implementation thing. Apparently there are tools that are *much* happier when pure declaration is identical to implementation, and otherwise cause problems. Not sure which though. I can't remember. – Cheers and hth. - Alf Oct 04 '16 at 09:37
  • @demonplus: I don't know, in the current case I am targeting a quite specific case, while the OP is targeting more advanced cases in his question. (imho) – arc_lupus Oct 04 '16 at 09:52

10 Answers10

16

From the caller's perspective, both the first and the second form are the same.

Since the integers are passed by value, even if the function modifies a and b, the modified values are copies of the original and won't be visible to the caller.

However, from the function implementer's perspective there's a difference. In fact, in the second form:

int add(const int a, const int b)

you will get a compiler error if you try to modify the values of a and b inside the function's body, as they are marked as const.

Instead, you can change those values if you omit the const.
Again, those modifications will not be visible to the caller.

Mr.C64
  • 41,637
  • 14
  • 86
  • 162
  • 2
    This. You should add the the `const`in this case [is *not* part of the function's signature](http://stackoverflow.com/a/3682076/321013). That's the main reason *I* see for not including it for these simple functions, since it's not "really there" from the callers perspective but just an implementation detail: And for such a simple function its an unnecessary complication. – Martin Ba Oct 04 '16 at 09:27
  • @MartinBa: Thanks for your comment. However, while in this super-simple case the const on the parameters in the function definition can be unnecessary, I think for more complex functions with more parameters marking them as const at the _implementation site_ can be helpful to catch bugs, e.g. making sure that those parameters are not modified by mistake and the modifications lost. I would omit the const at the declaration site (prototype) though, as it can be noisy/confusing for the caller. – Mr.C64 Oct 04 '16 at 09:30
7

Using int add(const int a, const int b) means that you cannot modify the input parameters within the function body.

Perhaps the compiler can make some optimisations based on that, so it ought therefore to be never slower than the non-const equivalent. But I have never observed this effect in practice.

Passing const parameters can also increase the stability of your code base, particularly in a collaborative project.

All this said though, I find it too verbose, rather unnecessary, and would use int add(int a, int b). Very occasionally, for particularly long functions, I exploit the fact that you can declare the function with non-const parameters, and define it with the parameters const.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • It is the same as declaring const local variables, and we're OK with using those (not sure if it may inhibit copy elision for user defined types though.) – juanchopanza Oct 04 '16 at 09:23
  • 1
    They're going to be copied either way, I see no optimisation possibility here but I'll leave that to the optimisation gods. – Hatted Rooster Oct 04 '16 at 09:23
  • How can it increase the stability of my code base? My current style is: Either I have a pointer as input to my function (which is not constant), or a value, which then is declared const. – arc_lupus Oct 04 '16 at 09:25
  • 1
    It can be reassuring in a particularly long function that the input parameters have not been messed about with. – Bathsheba Oct 04 '16 at 09:26
  • 2
    @SomeWittyUsername Pff, the question is about passing by value. Comments about passing by reference are irrelevant here. – juanchopanza Oct 04 '16 at 09:27
  • @juanchopanza The question is why not to use const when passing by value. And it's correctly answered by Mr.C64 below. – SomeWittyUsername Oct 04 '16 at 09:28
  • That would be a curious compiler which would use that local `const` as an optimization-tip instead of local analysis. – Deduplicator Oct 04 '16 at 09:30
  • When you write some really long function (although not recommended), you may forget about some modification of parameter and use it wrongly. Using `const int a` will prevent such situation, trough the whole function you can be sure the `a` is `a`. Also when you refactor type from `int` to something more complex later, the `const` may help a bit the compiler then... But the `int` itself as the basic native type is probably that special case, where there's hardly any benefit, except of exercising "use const whenever possible". – Ped7g Oct 04 '16 at 09:30
7

If you are actually struggling with correctness bugs in your codebase where const would have helped, then add const.

That said, there are related issues that you should consider. Top-level qualifiers of function parameters aren't part of the function type, so your function type is still just int(int, int). (The qualifiers only affect the parameter variables in the function definition.) That means that any declaration of the function also ignores qualifiers, so int add(int, int) and int add(const int, int) and int add(int, const int) all declare the same function. So you have to decide on a policy for how you write header files. And now you have three essential positions you can take:

  1. Always qualify in both declaration and definition. The upside is that this perhaps keeps code looking "consistent" (think copy/pasting when creating implementations). The downside is that the qualifiers have nothing to do with the interface, and are not at all enforcible (you can change the definition later!), so at best it's noise, at worst it's wrong.

  2. Qualify in the definition, but not in the other declarations. The upside is that this communicates the interface correctly and you still get const checking in the definition. The downside is that some people might be confused by the discrepancies in spelling. (Just like people may be confused that a static constexpr T foo; class member can be defined with const T C::foo;.)

  3. Don't qualify either. The upside is that it's consistent, clean, easy to remember and minimal. The downside is that you're missing out on correctness checks in your definition.

There's no right answer. If you're the codebase owner or project lead, you should decide based on what the biggest problems in your codebase and team are. (My personal position is to stick with (3) until you have a good reason to change.)

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • For the specific example in the question, qualifying the by-value parameters with const is actually confusing and misleading from the user perspective. The actual meaning of such qualification is that the copy is immutable which of course has nothing to do with the original object constness or lack of it. – SomeWittyUsername Oct 04 '16 at 10:32
1

I feel like everyone is dancing around this part of the answer... It's true that using const will keep the function from modifying the value of your int a & b while inside the function. This can be extremely useful, so use it as you wish, of the compiler allows it. But, the function caller will never know about any changes to a & b once the function finishes. So even if a & b are changed, no one except the defined function will know their updated values.

int funcB(int a, int b)
{
    a = a+1;
    b = b*b;
    return a+b;
}

void funcA()
{
    int s = 5;
    int t = 6;
    int result = funcB(s, t);
    printf("%f + %f = %f", s,t, result);
}

funcA prints: "5 + 6 = 42"

Const protection is often used when passing values by reference, ie:

int function(const int &a, const int &b) {}

This passes a reference of a and b to the function (ie, does not make copies of a and b but passes only a memory address of that variable, aka: the handle). When passing a variable by reference, any changes made to the variable are remembered outside the scope of the function and can change the way your program runs. This is generally undesired behavior. So if you rework funcB from above and pass by reference:

int funcB(int &a, int &b)
{
    a = a+1;
    b = b*b;
    return a+b;
}

funcA prints: "6 + 36 = 42"

If you add const correctness to funcB:

int funcB(const int &a, const int &b)
{
    a = a+1;
    b = b*b;
    return a+b;
}

I don't think the compiler will let you even do this since you would be explicitly trying to modify values that you've protected via const.

Another time when it may be really important to use const is when you're passing by pointer, instead of reference or copy...

int funcB(int *a, int *b)
{
    a = a+1;
    b = b*b;
    return a+b;
}

Unless you're a pointer expert, avoid passing pointers without const pretention. This func will likely attempt to iterate the index of your pointer arrays and you'd open yourself up to run time errors related to out of bound memory. You could accidently see memory from an entirely different program... but probably not.

Lastly, since you're just passing int, there's no practical need to pass by reference (which is done often to keep from adding complex data into memory because each non-reference or non-pointer pass to functions copies the value into memory for the life of the function being called) since the memory footprint of int is so small. Unless, you're working with specialized hardware that has extremely limited memory, then it may be useful; this won't apply to most standard computers and desktops made within the past 20 years, or smart phones.

Andrew
  • 1,423
  • 1
  • 17
  • 26
0
int add(const int a, const int b)
{
    return a+b;
}

Here const in used so that the function does not modify the original values of a and b by any chance. In the above example it does not make sense. But if it would have been an example like

int add(const int *a, const int *b)
{
    //*a = 10; //This will throw error. 
    return a+b;
}

In functions where objects,arrays or such data types are passed its a good approach to use const to avoid mutation of original data structure.

Ajay Pal
  • 543
  • 4
  • 13
0

If you want to be truly const correct, then you should add it, but in reality all it will do is make you type and read more.

Nothing will go faster, and while it could mean that your variables go into another location in memory, it's unlikely to on most modern machines.

What it will stop you doing is accidentally assigning them values, but as they're local to the function, it's relatively unimportant. What would matter is if they were references, as this demonstrates your intent to the caller to not change them.

UKMonkey
  • 6,941
  • 3
  • 21
  • 30
0

You can use const there if you like.

It is unlikely to speed up your program because any reasonable compiler can already see that no code path alters the value of a or b and make any optimisations it needs.

a and b are int, which are passed by value so making them const has no impact on the users of this function.

The only possible advantage is where your function is long and more complex and you want to avoid possible programming errors where the original values of a or b are changed during the function.

GrahamS
  • 9,980
  • 9
  • 49
  • 63
0

If you will use const then you cannot modify the value of a,b. Thats why we don't use const.

0

The primary purpose of constness is to provide documentation and prevent programming mistakes. Const allows you to make it clear to yourself and others that something should not be changed. Moreover, it has the added benefit that anything that you declare const will in fact remain const short of the use of forceful methods. It's particularly useful to declare reference parameters to functions as const references:

bool SomeFunction (const myObj& obj);

Here, a myObj object is passed by reference into SomeFunction. For safety's sake, const is used to ensure that SomeFunction cannot change the object--after all, it's just supposed to make sure that the object is in a valid state. This can prevent silly programming mistakes that might otherwise result in damaging the object (for instance, by setting a field of the class for testing purposes, which might result in the field's never being reset). Moreover, by declaring the argument const, users of the function can be sure that their object will not be changed and not need to worry about the possible side effects of making the function call.

moreover, The reason is that const for the parameter only applies locally within the function, since it is working on a copy of the data. This means the function signature is really the same anyways. It's probably bad style to do this a lot though. I personally tend to not use const except for reference and pointer parameters.

Wissam HANNA
  • 63
  • 14
0

as a law of thumb we are advised to use const as much as possible because we get a great help from the compiler so whenever we try to change a constant the mistake will be caught by the compiler; it's a good thing avoiding being caught in error-prones.

the second thing: a and b passed by value so they are created as local constants But as long as they are not changeable why we need copies??

  • the good thing is to pass a const reference which means never change parameters and avoid copies (by value):

    int add(const int& a, const int& b) // now there are no copies of a and b in addition we cannot modify a and be
    {
        return a+b;
    }
    
Raindrop7
  • 3,889
  • 3
  • 16
  • 27