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(constdouble 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.
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.
... 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?
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?
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.
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_)
{
constint& 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
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).
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(constint 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(constint argc, constchar* 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.
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.