Pass by const copy

I have never seen anyone pass by const copy and there probably is a reason. I know that the compiler ignores top level const-ness of function arguments. There are functions which take arguments without manipulating those arguments return the result, for example the C Standard Library funcion double sqrt (double x). The function shouldn't modify it's argument, but it can since the argument isn't const.

Take these two functions for example:

1
2
3
4
5
6
7
8
9
10
11
double square_root_1(double arg)
{
	arg = 7; // we won't get the desired results
	return arg * arg;
}

double square_root_2(const double arg)
{
	arg = 7; // will not compile
	return arg * arg;
}


I have compiled the code above and here's what I get:

MSVC 2013
C3892: 'arg' : you cannot assign to a variable that is const
GCC 4.8.2
error: assignment of read-only parameter 'arg'

So isn't it better to pass by const copy to make sure that you (or someone else) don't by accident modify the argument? The only disadvantage I see is that it makes the code too verbose.

Thanks in advance to anyone who replies!
Last edited on
The function can't make changes to the object in the caller's context either way; it just gets a copy of the original. So passing by value or passing by const qualified value would make no difference to the caller.

The use of const in a parameter passed by value only means that the function would not be able to modify its own copy of the object. My take on this: what a function does with the copy of the object it receives is an implementation detail, internal to the function, and should not appear in its interface.
@JLBorges

Thank you for the quick reply.

... the function would not be able to modify its own copy of the object.
Which is exactly what I want. Wouldn't it be better for all function that don't need to modify their arguments, have their arguments passed by const copy?
Last edited on
Wouldn't it be better for all function that don't need to modify their arguments, have their arguments passed by const copy?
If you are passing primitive types, yes. For complex types const reference is usually better unless you are in multithreading enviroment.
@MiiNiPaa

Thanks for replying.

From all the code that I have read from other people, libraries, open source projects, I've noticed that nobody passes by const value. It's kind of weird if I'm the only one doing it. So should I pass by const value?
Last edited on
I would recommend against it. As @JLBorges said, we don't really need to know the implementation details of your class. Considering that it makes no real difference to anyone except the creator of the class, consider pleasing the many (i.e. the people using your library) rather than the few (i.e. you).

Then again, there is nothing stopping you if you want to do it. Apart from loss of efficiency with non-primitive types, there are no real drawbacks.
I've noticed that nobody passes by const value.
I do that all the time. So I second that.

The problem is that const makes your code safe, but is sometimes inconvenient to use (esp. if you want some 'dirty tricks').

const correctness is usually a sign of a well thought design
So should I pass by const value?
Probably not. You are exposing part of implementation, which should be hidden, to the user (as function declaration are always visible) and who cares if function changes something passed by value?
There is more: what if you will find that it is will be better to change passed value? You will have to make another copy of variable (you cannot just change input parameter type as this will break your library interface).
Herb Sutter strongly advisies against it, for example.

If you really want to make sure that nobody accidently changes variable in function (at leas for now), bind this variable to const reference and use it:
1
2
3
4
5
void foo(int bar_)
{
    const int& bar = bar_;
    //use bar only
}
after testing, when you are ready to release remove reference and change parameter name to reference name:
1
2
3
4
void foo(int bar)
{
    //Now all code which worked with reference works with value
    //As reference was const no code changes this variable 


http://www.devx.com/tips/Tip/26546
http://www.gotw.ca/gotw/006.htm
Last edited on
Thank you all for replying!

@NT3

Considering that it makes no real difference to anyone except the creator of the class, consider pleasing the many (i.e. the people using your library) rather than the few (i.e. you).


That answered my question.
You can declare your functions without using const and put const qualifiers in the function implementation:

1
2
3
4
5
6
7
8
int myfunc(int param); // forward declaration (header file?)


int myfunc(const int param)
{
    // cant accidentally corrupt param here
    return answer;
}


So you don't have to expose the fact that, internally, you treat your parameter as const if you don't want to.

I think it is a good practice, especially for complex functions. It is all too easy to use a parameter called i as the iterator of a for-next loop corrupting its value:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

std::vector<std::string> vec;

bool crossreference(int i, const std::string& s)
{
    bool found = false;
    
    // do some processing here
    
    for(i = 0; i < vec.size(); ++i) // forgot to declare i
    {
        if(vec[i] == s)
            found = true;
    }
    
    // do some more processing here
    
    return (i >= 0 && found) || !found; // oops i has been badly corrupted
}


I don't use this all the time but I do sometimes use it in complex functions where the input parameter *needs* to remain constant. Or you might make a parameter const while trying to comprehend someone else's code just to see if and how the parameters are modified within the function.

I also tend to use it for main():
1
2
3
4
int main(const int argc, const char* argv[])
{
    // process arguments here
}


So I would recommend you don't use const in the function declaration (headers) but do use it in the function definition if you feel it makes the code more robust.
Last edited on
@Galik

I think that your solution of using const qualifiers for the arguments in the function definition only is the best and the one which I will use from now on.
Last edited on
Topic archived. No new replies allowed.