I read that they are conceptually equal. In practice, is there any occasion that
foo(T t)
is preferred over
foo(const T& t)
? and why?
Thanks for the answers so far, please note I am not asking the difference between by-ref and by-val.
Actually I was interested in the difference between by-const-ref and by-val.
I used to hold the oipinion that by-const-ref can replace by-value in call cases since even Herb Sutter and Bjarne said they are conceptually equal, and "by ref"(be it const) implies being faster. until recently, I read somewhere that by-val may be better optimized in some cases.
Then when and how?
They're not conceptually equal at all...
The former creates a copy of the object inside the function. This implies that the value can be modified in the function safely. It also implies that a full copy of the object occurred, which can be a problem if the object is large.
The latter creates an alias to the object and states that it cannot be modified within the object. No copying occurs, but each access to the object inside the function will require a dereference. The compiler takes care of this for us, but it's still important to know.
The difference becomes very important if you have a type that is normally passed in registers. For example, integers, floating point numbers, and even 4-float vectors on some platforms. Performance concerns dictate that you want to object to stay in a register for as long as possible without writing itself back to memory, and pass by value makes this much more likely.
So for basic types (char, short, int, long, float, double), you should always prefer pass by value unless you specifically need to use a reference to store a value for use after the function exits. For full objects, generally prefer to pass by const reference.
If the most straightforward implementation of the function involves modifying the parameter value locally, then it makes sense to pass it by value rather than by const reference
For example, the one line version of strcpy:
If you took in the pointers as const references, you would need to copy them to temporaries in the body of your program, rather than letting the paramater passing mechanism do it for you.
Two very specific cases:
When you are writing assignment operators with strong exception guarantees you can either write them like
or you can recognize that the first thing that happens is that you make a copy and just have it done as part of the call
If you have a smart pointer with ownership semantics, e.g.
auto_ptr
, and you want to transfer ownership to the called function you should pass it by value. Of course 8 people will now quickly point out that you probably don't want to useauto_ptr
and they're probably right, but sometimes you don't make that choice.While not at all specific, I frequently end up passing smallish objects around by value when that saves me an allocation on the heap. Not only does the actual allocation and eventual deallocation take time but referencing everything through a pointer does nothing to improve your data locality. It might in other words make a difference to your performance. Exactly where the break-even point is will depend on your application, but I would personally don't hesitate to pass an object that is a few pointer sizes large.
If you want to locally modify
t
(without affecting the original) in the body of your method (say in the process of calculating something), the first method would be preferential.Built-in types and small objects (such as STL iterators) should normally be passed by value.
This is partly to increase the compiler's opportunities for optimisation. It's surprisingly hard for the compiler to know if a reference parameter is aliasing another parameter or global - it may have to reread the state of the object from memory a number of times through the function, to be sure the value hasn't changed.
This is the reason for C99's
restrict
keyword (the same issue but with pointers).Don't forget that there are cases where there is a difference - when you're dealing with objects that have strange copy/assignment semantics.
auto_ptr<>
is the classic example - pass those around by value without thinking about the consequences and you may end up with a mess.