5

Consider this function declaration:

int IndexOf(const char *, char);

where char * is a string and char the character to find within the string (returns -1 if the char is not found, otherwise its position). Does it make sense to make the char also const? I always try to use const on pointer parameters but when something is called by value, I normally leave the const away.

What are your thoughts?

helpermethod
  • 59,493
  • 71
  • 188
  • 276
  • 5
    Why the close vote? Seems like a valid question to me. – Graeme Perrow Dec 21 '10 at 14:26
  • possible duplicate of [Use of 'const' for function parameters](http://stackoverflow.com/questions/117293/use-of-const-for-function-parameters) – John Dibling Dec 21 '10 at 15:11
  • 1
    As you can see, this is more a religious issue than anything else. It has also been asked before. Arguments can be made for or against either side. I suggest you read the link I provided above, and decide for yourself. – John Dibling Dec 21 '10 at 15:12
  • @John Dibling: The other question was really about making arguments `const`. This is just a bit of confusion, see the "make the char also `const`" quote: it presumes that the first argument is already `const`. It isn't, but the string it points to is. – MSalters Dec 21 '10 at 15:19
  • @MSlaters: I'm not seeing the difference? This question seemed to ask the exact same question by my reading. – John Dibling Dec 21 '10 at 15:22

9 Answers9

4

It doesn't make sense because the caller won't be affected if you modify the second parameter's value.

Further, if you need to modify this argument inside the function it may help you save a few bytes on the stack rather than having to declare a separate local variable.

The below code is a good example of modifying an argument instead of having a local variable:

void foo (int count) {
  while (count--) {
    do_something();
  }
}

However, if your function is longer and you don't intend to modify its arguments, it may be rewarding in terms of maintenance to mark the corresponding arguments as const, but only in its definition, not in the declaration that resides in a header file. If you later decide that an argument shouldn't be const, you only have to change it in the definition.

Blagovest Buyukliev
  • 42,498
  • 14
  • 94
  • 130
  • Agree, I tend to remove such consts that does not make sense and may confuse. – merxbj Dec 21 '10 at 13:56
  • 3
    Don't agree: Of course it won't affect the caller, but it *will* affect the maintainance programmer. Imagine `foo` is five screens long, and you need the values of `count` somewhere. You'd have to parse the whole function to see if someone modified it somewhere. And if you *remove* `const` keywords like that, you have to do that for each and every parameter you use when you change the function. Better mark a parameter as const if you don't intend to change it. – Niki Dec 21 '10 at 14:28
  • 1
    @nikie: Your argument stopped being convincing when you said `foo` is five screens long. The problem isn't that a parameter isn't const, it's that you've got a five-page long function. Refactor your code, win-win. – GManNickG Dec 21 '10 at 17:08
  • @GMan: five screens might be exaggerated, true. But the implementation of a moderately complex algorithm can easily be hundred lines or longer, without many oportunities for refactoring. For examples, look at the source code for FLANN, libsvm, boost or FFTW. – Niki Dec 22 '10 at 12:11
  • @nikie: Of those, I'm familiar with Boost, and I don't know of many long functions. – GManNickG Dec 22 '10 at 12:30
  • @GMan: Look at the regex parser in Boost. More than one > 100 line function in there. Or, look at your favorite PNG or JPEG decoder. I'm willing to bet you'll find a few long functions in there. – Niki Dec 22 '10 at 12:52
  • @nikie: Probably. Even if it's the case, I maintain such functions not only be broken up, but that we shouldn't make generalizations based off a few very special cases. – GManNickG Dec 22 '10 at 12:56
4

Assuming you don't intend to adjust the value of either parameter:

I would have the function definition as:

int IndexOf( const char * const , const char )
{
    //...
}

But keep the function declaration as:

int IndexOf( const char * , char );

In other words:
I'd reveal the bare minimum level of const in the header, but then use the maximum possible level of const in the implimentation.

Why?

  1. Seperating the header and implimentation allows me to change the parameters that are const in the implimentation without ever touching the header (except those that are vitally const, which should require a header change).
  2. It's makes the code more self-documenting.
  3. It makes it harder to introduce bugs without the compiler catching them as errors.
  4. It makes it harder for other programmers to introduce bugs when making future changes.

Making a pass-by-value paramter const or not has "no effect" in terms of affecting the caller of the function - which is why you should keep them out the header - but they can make your implimentation more robust and easier to maintain.

Obviously, if it's more useful to change the parameter rather than copying it into another local variable then don't make it const for the sake of doing so.

DMA57361
  • 3,600
  • 3
  • 27
  • 36
  • actually, that's undefined behaviour; see C99 6.5.2.2 §9 (or 6.7 §4), 6.7.5.3 §15, 6.7.3 §9 – Christoph Dec 21 '10 at 19:23
  • Your answer is correct for C++. Top-level consts are ignored in function declarations. For example, void f(int); is identical to void f(const int);. Of course a const pointer or const reference is not considered top-level. It is strongly recommended to omit top-level consts in function declarations. – Tamas Demjen Dec 21 '10 at 20:58
4

Contrary to my co-answerers, I'd make the char const. After all, you don't want to change the character you're looking for in mid-search, do you? And since doing so inadvertently has a good chance of messing up your algorithm, const helps to make your code robust and easy to maintain.

Christian Severin
  • 1,793
  • 19
  • 38
3

For the example you gave the answers make sense, but in the more general case of passing by value there can be some instances where const might be helpful.

Generally this might be for non POD types where potentially even passing by value doesn't guarantee no visible side effects from changes. Furthermore if you absolutely know that your implementation won't be wanting to change it marking it const can help the compiler find bugs if/when someone accidentally changes the value later.

I tend to live by the rule "mark it const unless there's a reason for it to not be const"

Flexo
  • 87,323
  • 22
  • 191
  • 272
2

I don't think it is necessary, as the char's value will be copied and any change to it won't be reflected outside of its scope.

alex
  • 479,566
  • 201
  • 878
  • 984
2

It doesn't matter, so long as you are consistent.

As you can see, this question is a religious one. People come down on either side, and tend to fervently disagree with the opposing side.

Arguments can be made for or against either side. The arguments that are made can be contradicted.

For example, the arguments in the "make it const" camp tend to argue that it makes the code more self-documenting for maintenance programmers working on that function. This may well be true, and you might decide this is a good enough reason to mark your by-value parameters as const. The other side of this coin however is that you may decide one day that you do need to modify the variable in the function, which would require that you change the signature, or make a local copy. In addition, which marking is as const does add some documentation for the maintenance programmer, it also adds documentation for the client programmer -- but this documentation is misleading at best. It implies certain semantics to the caller that do not exist.

But whatever you do, you need to be consitant. Either make all your by-value parameters const, or none of them. Inconsitancy will destroy any of the documentary benefits you gain by taking either side.

John Dibling
  • 99,718
  • 31
  • 186
  • 324
1

If it's a 3 line function, the const doesn't help much.

But if you have to understand and maintain a 300 line function, it can be a very important clue that a local variable or parameter will not be changed before line 289, where it is used.

Niki
  • 15,662
  • 5
  • 48
  • 74
1

Pro const:

  • prevents the argument from being accidentally modified within the callee

Contra const:

  • adds clutter without providing useful information to the caller
  • implementation changes (ie removing the qualifier) will change the interface

The ideal solution would be to provide the const only in the declaration which is part of the function definition. However, the C standard does not allow this; it will work as expected in all reasonable implementations of the C language, though.

Christoph
  • 164,997
  • 36
  • 182
  • 240
0

I'd say const would add absolutely nothing to your code.

mingos
  • 23,778
  • 12
  • 70
  • 107
  • 6
    If argument is not changed inside a function it should be `const`. – Pawel Zubrycki Dec 21 '10 at 14:16
  • @Pawel: yes, but it's not something the caller cares about, it's more of an inner implementation issue. – Blagovest Buyukliev Dec 21 '10 at 14:23
  • 4
    @Blagovest: If it could be `conts` it should be `const`. Thats my opinion. But you're right that this changes nothing - just a matter of good coding style IMO. – Pawel Zubrycki Dec 21 '10 at 14:25
  • @Pawel: following that logic, most functions would take const parametres. The impact on what the function does is nil, so IMO it can and should be omitted. – mingos Dec 21 '10 at 14:26
  • 2
    @mingos: `const` never adds anything to your code. It never has any effect on what the function does. It only tells the compiler (and the next programmer modifying your code) that you *don't* intend to change the local or parameter. (IMHO const should be default and mutable values should be marked, but that's another discussion.) – Niki Dec 21 '10 at 14:31
  • I see the downvote as unjustified, but so be it. `const` is useful when you pass a reference to an object outside the function's scope and want to prevent that from being modified. Here, it's passed by value and the function will probably use it once: in a `strchr` call or something. `const` is useless in this case and just adds an extra distraction to confuse whoever reads the code. – mingos Dec 21 '10 at 15:05