views:

181

answers:

6

I know there are few question about const correctness where it is stated that the declaration of a function and its definition do not need to agree for value parameters. This is because the constness of a value parameter only matters inside the function. This is fine:

// header
int func(int i);

// cpp
int func(const int i) {
    return i;
}

Is doing this really a best practice? Because I've never seen anyone do it. I've seen this quotation (not sure of the source) in other places this has been discussed:

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

"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."

The second paragraph says to not put the const in the declaration. I assume this is because the constness of a value parameter is meaningless as part of a interface definition. It is an implementation detail.

Based on this recommendation, is it also recommended for the pointer values of pointer parameters? (It is meaningless on a reference parameter since you can't reassign a reference.)

// header
int func1(int* i);
int func2(int* i);

// cpp
int func1(int* i) {
    int x = 0;

    *i = 3; // compiles without error
    i = &x; // compiles without error

    return *i;
}
int func2(int* const i) {
    int x = 0;

    *i = 3; // compiles without error
    i = &x; // compile error

    return *i;
}

Summary: Making value parameters is useful to catch some logic errors. Is it a best practice? Do you go to the extreme of leaving the const out of the header file? Is it just as useful to const pointer values? Why or why not?

Some references:

http://stackoverflow.com/questions/1554750/c-const-keyword-use-liberally http://stackoverflow.com/questions/117293/use-of-const-for-function-parameters

An example of when const value parameters are useful:

bool are_ints_equal(const int i, const int j) {
    if (i = j) { // without the consts this would compile without error
        return true;
    } else {
        return false;
    }
    // return i = j; // I know it can be shortened
}
+3  A: 

I've read many times that making value parameters in a function const is a bad thing to do because it's unnecessary.

However, I find it occasionally helpful to me as a check that my implementation doesn't do something I don't intend (as in the example at the end of your question).

So, while it may not add value to the caller, it does sometimes add a small bit of value to me as an implementer, and it doesn't take anything away from the caller. So I see no harm using it.

For example, I may be implementing a C function that takes a couple pointers to a buffer - a pointer to the start, and a pointer to the end. I'm going to put data in the buffer, but want to ensure that I don't overrun the end. So inside the function there's code that will increment a pointer as I'm adding data to it. Making the pointer to the end of the buffer a const parameter will ensure that I don't code up a bug that accidentally increments the end boundary pointer instead of the pointer I really should be incrementing.

So a fillArray function with a signature like this:

size_t fillArray( data_t* pStart, data_t* const pEnd);

will prevent me from accidentally incrementing pEnd when I really mean to increment pStart. It's not a huge thing, but I'm pretty sure everyone who has programmed for any period of time in C has run across such a bug.

Michael Burr
Excellent. I was looking for a good example of a const pointer value.
jmucchiello
+2  A: 

My take on it:

It's not a bad idea, but the issue is minor and your energy might be better spent on other things.

In your question you provided a good example of when it might catch an error, but occasionally you also end up doing something like this:

void foo(const int count ...)
{
   int temp = count;  // can't modify count, so we need a copy of it
   ++temp;

   /* ... */
}

The pros and cons are minor either way.

luke
+1 for saying it's not a bad idea, and for noting the issue is minor. But before you would copy the parameter inside, i would just remove the const (except perhaps if you would copy "count" always, as a principle of not operating on a parameter, and not only because of the const preventing you)
Johannes Schaub - litb
Usually when you modify the variable like this you're changing the semantic meaning. For instance: void foo(const int index0based){const int index1based = index0based + 1;} You could just call it index and change it, but this is much clearer for the poor maintenance programmer who comes along in 5 years.
Bill
@Bill, excellent point!
Johannes Schaub - litb
Bill- My example is contrived, but you might be right for many cases. The issues of a maintenance programmer are near and dear to my heart ;)
luke
Actually, I've seen similar code to your example. A count if items is passed in, and instead of making a local `int currentCount = count;`, the parameter was used and adjusted while the function went about its business... very confusing!
Bill
A: 

Unfortunately, some compilers (I'm looking at you, Sun CC!) incorrectly differentiate between arguments declared const and ones not declared so, and you can get errors about undefined functions.

Hyman Rosen
A: 

It's good practice for the same reason that declaring any object const is good practice if you don't want it to change - it makes sure that the value won't change when you don't expect it to.

Mike Seymour
But most people never do this. I had never encountered this concept before today and I've been banging on C++ for over 15 years. Before that I would considered void f(const int foo) redundant or interface clutter. This should be the highest rated "hidden feature of C++" where ever that question is.
jmucchiello
A: 

I like const correctness for situations like this:
void foo(const Bar &b) //I know b cannot be changed
{
//do something with b
}

This lets me use b without fear of modifying it, but I don't have to pay the cost of a copy constructor.

Stephen Newell
We are not talking about reference parameters. Value parameters only.
jmucchiello
A: 

I think this is dependent on your personal style.

It doesn't add or subtract to what clients can pass to your function. In essence it's like a compile-time assertion. If it helps you to know that value won't change, go ahead and do it, but I don't see a big reason for others to do it.

One reason I might not do it is that the const-ness of the value parameter is an implementation detail that your clients don't need to know about. If you later (purposely) change your function so that it actually does change that value, you will need to change the signature of your function, which will force your clients to re-compile.

This is similar to why some people recommend having no public virtual methods (the functions virtual-ness is an implementation detail that should be hidden from clients), but I'm not in that particular camp.

JohnMcG
Reread the question. The header file doesn't have the const because, as you say, the caller doesn't care whether the implementation modifies a local variable. This is a question strictly about whether it is worth it on the implementation side.
jmucchiello