I read that they are conceptually equal. In practice, is there any occasion that
foo(T t)
is preferred over
foo(const T&
Some routines require a copy, and so should not be pass by reference. For example, a chess playing program's move generator might need a copy of the current position to work on (recursively) rather than actually modifying the original instance of the position.
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.
Boost.CallTraits is a lesser-known but helpful facility for doing parameter and result passing with what should be the most efficient method available for the type in question.
Another case that hasn't been mentioned is heavy use of the object. Let's say you pass a struct with 5 ints as members. If you are going to be accessing all 5 quite a lot in your function, there comes a point when the dereference cost outweighs the copy cost. However, you'd have to run a profiler to know when that is.
I should point out, though, that things like STL containers, which allocate memory on the heap, should almost never be passed by value if avoidable, because heap allocation is very slow compared to stack allocation.
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:
char *strcpy(char *dest, const char *src)
{
while (*dest++ = *src++);
return s1;
}
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.
Here is a case when you don't have other option but only to pass a parameter by value. Of course boost does handle this. But without boost we have to pass a Value to function by value.
class Test
{
public:
Test()
{
std::set<std::string> values;
values.insert("A");
values.insert("V");
values.insert("C");
std::for_each(values.begin(), values.end(),
bind1st(mem_fun(&Test::process), this));
}
private:
void process( std::string value )
{
std::cout << "process " << value << std::endl;
}
};