views:

3438

answers:

8

Is it better in C++ to pass by value or pass by constant reference?

I am wondering which is better practice. I realize that pass by constant reference should provide for better performance in the program because you are not making a copy of the variable.

A: 

Sounds like you got your answer. Passing by value is expensive, but gives you a copy to work with if you need it.

GeekyMonkey
I'm not sure why this was voted down? It makes sense to me. If you are going to need the value currently stored, then pass by value. If not, pass the reference.
Totty
It is totally type dependent. Doing a POD (plain old data) type by reference can in fact reduce performance by causing more memory accesses.
Torlack
Obviously passing int by reference doesn't save anything! I think the question implies things that are bigger than a pointer.
GeekyMonkey
It isn't that obvious, I've seen a lot of code by people who don't truly understand how computers work passing simple things by const ref because they have been told that is the best thing to do.
Torlack
+8  A: 

Depends on the type. You are adding the small overhead of having to make a reference and dereference. For types with a size equal or smaller than pointers that are using the default copy ctor, it would probably be faster to pass by value.

Lou Franco
For non-native types, you might (depending on how well the compiler optimises code) get a performance increase using const references instead of just references.
OJ
+20  A: 

Actually, any modern compiler should be able to figure out when passing by value is expensive, and implicitly convert the call to use a const ref.

In theory. In practice, the standards committee unfortunately made some strange requests that forbid the compiler to omit calling a copy constructor1. This means that in practice, the compiler won't figure this out for you although it could, and trivially.

So: you've got no choice but to pass by const reference if you don't want to uselessly squander resources. It's actually best-practice to pass by const ref. Scott Meyers (in Effective C++) recommends that you use pass by const ref for all types, except for builtin types (char, int, double, etc.), for iterators and for function objects (classes deriving from std::*_function).


1) I oversimplify, of course. There are very good reasons for this requirement. It just makes automated optimizations so darn much harder.

Konrad Rudolph
hmmm... I am not sure that it is worth to pass by ref. double-s
sergdev
As usual, boost helps here. http://www.boost.org/doc/libs/1_37_0/libs/utility/call_traits.htm has template stuff to automatically figure out when a type is a builtin type (useful for templates, where you sometimes cannot know that easily).
CesarB
This answer misses an important point. To avoid slicing, you must pass by reference (const or otherwise). See http://stackoverflow.com/questions/274626/what-is-the-slicing-problem-in-
ChrisN
@Chris: right. I left the whole part of polymorphism out because that's a completely different semantics. I believe the OP (semantically) meant “by value” argument passing. When other semantics are required, the question doesn't even pose itself.
Konrad Rudolph
+2  A: 

As a rule passing by const reference is better. But if you need to modify you function argument locally you should better use passing by value. For some basic types the performance in general the same both for passing by value and by reference. Actually reference internally represented by pointer, that is why you can expect for instance that for pointer both passing are the same in terms of performance, or even passing by value can be faster because of needless dereference.

sergdev
If you need to modify the callee's copy of the parameter, you could make a copy in the called code rather than passing by value. IMO you generally shouldn't choose the API based on an implementation detail like that: the calling code's source is the same either way, but its object code isn't.
Steve Jessop
If you pass by value copy is created. And IMO there is no matter in which way you create a copy: via argument passing by value or locally - this is what concerns the C++. But from the design point of view I agree with you. But I describe C++ features here only and don't touch design.
sergdev
+2  A: 

As it has been pointed out, it depends on the type. For built-in data types, it is best to pass by value. Even some very small structures, such as a pair of ints can perform better by passing by value.

Here is an example, assume you have an integer value and you want pass it to another routine. If that value has been optimized to be stored in a register, then if you want to pass it be reference, it first must be stored in memory and then a pointer to that memory placed on the stack to perform the call. If it was being passed by value, all that is required is the register pushed onto the stack. (The details are a bit more complicated than that given different calling systems and CPUs).

If you are doing template programming, you are usually forced to always pass by const ref since you don't know the types being passed in. Passing penalties for passing something bad by value are much worse than the penalties of passing a built-in type by const ref.

Torlack
Note on terminology: a struct containing a million ints is still a "POD type". Possibly you mean 'for built-in types it is best to pass by value'.
Steve Jessop
Terminology corrected.
Torlack
Great explanation for the behind-the-scene mechanism! +1
kizzx2
+1  A: 

As a rule of thumb, value for non-class types and const reference for classes. If a class is really small it's probably better to pass by value, but the difference is minimal. What you really want to avoid is passing some gigantic class by value and having it all duplicated - this will make a huge difference if you're passing, say, a std::vector with quite a few elements in it.

Peter
+10  A: 

Edit: New article by Dave Abrahams on cpp-next:

Want speed? Pass by value.


Pass by value for structs where the copying is cheap has the additional advantage that the compiler may assume that the objects don't alias (are not the same objects). Using pass-by-reference the compiler cannot assume that always. Simple example:

foo * f;

void bar(foo g) {
    g.i = 10;
    f->i = 2;
    g.i += 5;
}

the compiler can optimize it into

g.i = 15;
f->i = 2;

since it knows that f and g doesn't share the same location. if g was a reference (foo &), the compiler couldn't have assumed that. since g.i could then be aliased by f->i and have to have a value of 7. so the compiler would have to re-fetch the new value of g.i from memory.

For more pratical rules, here is a good set of rules found in Move Constructors article (highly recommended reading).

  • If the function intends to change the argument as a side effect, take it by non-const reference.
  • If the function doesn't modify its argument and the argument is of primitive type, take it by value.
  • Otherwise take it by const reference, except in the following cases
    • If the function would then need to make a copy of the const reference anyway, take it by value.

"Primitive" above means basically small data types that are a few bytes long and aren't polymorphic (iterators, function objects, etc...) or expensive to copy. In that paper, there is one other rule. The idea is that sometimes one wants to make a copy (in case the argument can't be modified), and sometimes one doesn't want (in case one wants to use the argument itself in the function if the argument was a temporary anyway, for example). The paper explains in detail how that can be done. In C++1x that technique can be used natively with language support. Until then, i would go with the above rules.

Examples: To make a string uppercase and return the uppercase version, one should always pass by value: One has to take a copy of it anyway (one couldn't change the const reference directly) - so better make it as transparent as possible to the caller and make that copy early so that the caller can optimize as much as possible - as detailed in that paper:

my::string uppercase(my::string s) { /* change s and return it */ }

However, if you don't need to change the parameter anyway, take it by reference to const:

bool all_uppercase(my::string const& s) { 
    /* check to see whether any character is uppercase */
}

However, if you the purpose of the parameter is to write something into the argument, then pass it by non-const reference

bool try_parse(T text, my::string &out) {
    /* try to parse, write result into out */
}
Johannes Schaub - litb
A: 

Awesome, thanks to all the people.