Possible Duplicate:
Is it better in C++ to pass by value or pass by constant reference?
I'm aware of the differences of passing by value, pointer and reference in C++, and I'd consider passing objects by value (instead of const reference) in C++ to be almost always a programming error.
void foo(Obj o); ... // Bad
void foo(const Obj &o); ... // Better
The only case I can think of where it might be appropriate to pass by value instead of const reference is where the object is smaller than a reference, and passing by value is therefore more efficient.
But, surely this is the sort of thing that compilers are built to determine?
Why does C++ actually need pass by value AND pass by const reference, and - are compilers allowed to automatically convert the call to (and from) a const reference if appropriate?
(There seem to be 100s of C++ calling convention question, asking about the differences between (say) value and reference - but I couldn't find one that asked "why?".)
The reason is simple: if you passed by value, a copy of the object had to be made and, except for very small objects, this is always more expensive than passing a reference.
One of the advantages of pass-by-value is that a function is free to modify a parameter without inadvertently changing the data at the calling location. Another advantage is that the function argument may be any expression - not just a variable.
By definition, pass by value means you are making a copy in memory of the actual parameter's value that is passed in, a copy of the contents of the actual parameter. Use pass by value when when you are only "using" the parameter for some computation, not changing it for the client program.
pass-by-value makes a shallow-copy of the object. On the other side, pass-by-reference does not make any copy, it gets the reference of the object itself by just renaming it, so no any copying operation.
The question of when passing by value might be better than by const reference has different answers with different versions of the standard.
In the good old C++03, and a few years ago, the recommendation would be to pass anything that does not fit in a register by const reference. In this case, the answer would be:
Obj
fits in a register and passing by value and passing by value will be more efficientStill in C++03, in the last years (absurd as it seems some articles recommended this almost 10 years back, but there was no real consensus),
With the approval of the new C++11 standard, and increasing compiler support for rvalue-references, in many cases even when the copy cannot be elided, and again
As of the question of why the two different calling conventions, they have different goals. Passing by value allows the function to modify the state of the argument without interfering with the source object. Additionally, the state of the source object will not interfere with the function either (consider a multithreaded environment, and a thread modifying the source while the function is still executing).
Certainly one reason C++ has pass-by-value is because it inherited it from C, and removing that could break code for little gain.
Secondly as you note, for types that are smaller than a reference passing by value would be less efficient.
Another less obvious case however is if you have a function that needs a copy of its argument for some reason:
void foo(const Obj& obj)
{
if(very_rare_check()) return;
Obj obj_copy(obj);
obj_copy.do_work();
}
In this case note that you're forcing a copy. But suppose you call this function with the result of another function that returns by value:
Obj bar() { return Obj(parameters); }
And call it thusly: foo(bar());
Now when you use the const reference version, the compiler will end up making two objects: The temporary, and the copy in foo
. If however you passed by value the compiler can optimize away all the temporaries to the location used by the by-value parameter of foo
.
There's a great article about this and move semantics in general at http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/
Finally the canonical way to implement certain operators is to use pass-by-value to avoid copies inside the operator:
Obj operator+(Obj left, const Obj& right)
{
return left += right;
}
Note how this lets the compiler generate the copy in the parameter rather than forcing a copy or temporary object within the operator's code itself.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With