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

C++VariablesPass by-ReferenceConstantsPass by-Value

C++ Problem Overview


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.

C++ Solutions


Solution 1 - C++

It used to be generally recommended best practice1 to use pass by const ref for all types, except for builtin types (char, int, double, etc.), for iterators and for function objects (lambdas, classes deriving from std::*_function).

This was especially true before the existence of move semantics. 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.

With C++11, we have gained move semantics. In a nutshell, move semantics permit that, in some cases, an object can be passed “by value” without copying it. In particular, this is the case when the object that you are passing is an rvalue.

In itself, moving an object is still at least as expensive as passing by reference. However, in many cases a function will internally copy an object anyway — i.e. it will take ownership of the argument.2

In these situations we have the following (simplified) trade-off:

  1. We can pass the object by reference, then copy internally.
  2. We can pass the object by value.

“Pass by value” still causes the object to be copied, unless the object is an rvalue. In the case of an rvalue, the object can be moved instead, so that the second case is suddenly no longer “copy, then move” but “move, then (potentially) move again”.

For large objects that implement proper move constructors (such as vectors, strings …), the second case is then vastly more efficient than the first. Therefore, it is recommended to use pass by value if the function takes ownership of the argument, and if the object type supports efficient moving.


A historical note:

In fact, 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 if possible.

In theory. In practice, compilers can’t always change this without breaking the function’s binary interface. In some special cases (when the function is inlined) the copy will actually be elided if the compiler can figure out that the original object won’t be changed through the actions in the function.

But in general the compiler can’t determine this, and the advent of move semantics in C++ has made this optimisation much less relevant.


1 E.g. in Scott Meyers, Effective C++.

2 This is especially often true for object constructors, which may take arguments and store them internally to be part of the constructed object’s state.

Solution 2 - C++

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 */
}

Solution 3 - C++

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.

Solution 4 - C++

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.

Solution 5 - C++

This is what i normally work by when designing the interface of a non-template function:

  1. Pass by value if the function does not want to modify the parameter and the value is cheap to copy (int, double, float, char, bool, etc... Notice that std::string, std::vector, and the rest of the containers in the standard library are NOT)

  2. Pass by const pointer if the value is expensive to copy and the function does not want to modify the value pointed to and NULL is a value that the function handles.

  3. Pass by non-const pointer if the value is expensive to copy and the function wants to modify the value pointed to and NULL is a value that the function handles.

  4. Pass by const reference when the value is expensive to copy and the function does not want to modify the value referred to and NULL would not be a valid value if a pointer was used instead.

  5. Pass by non-const reference when the value is expensive to copy and the function wants to modify the value referred to and NULL would not be a valid value if a pointer was used instead.

Solution 6 - C++

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

Solution 7 - C++

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.

Solution 8 - C++

Pass by value for small types.

Pass by const references for big types (the definition of big can vary between machines) BUT, in C++11, pass by value if you are going to consume the data, since you can exploit move semantics. For example:

class Person {
 public:
  Person(std::string name) : name_(std::move(name)) {}
 private:
  std::string name_;
};

Now the calling code would do:

Person p(std::string("Albert"));

And only one object would be created and moved directly into member name_ in class Person. If you pass by const reference, a copy will have to be made for putting it into name_.

Solution 9 - C++

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.

Solution 10 - C++

Pass by referece is better than pass by value. I was solving the longest common subsequence problem on Leetcode. It was showing TLE for pass by value but accepted the code for pass by reference. Took me 30 mins to figure this out.

Solution 11 - C++

Simple difference :- In function we have input and output parameter , so if your passing input and out parameter is same then use call by reference else if input and output parameter are different then better to use call by value .

example void amount(int account , int deposit , int total )

input parameter : account , deposit output paramteter: total

input and out is different use call by vaule

  1. void amount(int total , int deposit )

input total deposit output total

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMatt PascoeView Question on Stackoverflow
Solution 1 - C++Konrad RudolphView Answer on Stackoverflow
Solution 2 - C++Johannes Schaub - litbView Answer on Stackoverflow
Solution 3 - C++Lou FrancoView Answer on Stackoverflow
Solution 4 - C++TorlackView Answer on Stackoverflow
Solution 5 - C++Martin GView Answer on Stackoverflow
Solution 6 - C++GeekyMonkeyView Answer on Stackoverflow
Solution 7 - C++sergtkView Answer on Stackoverflow
Solution 8 - C++Germán DiagoView Answer on Stackoverflow
Solution 9 - C++PeterView Answer on Stackoverflow
Solution 10 - C++aaaView Answer on Stackoverflow
Solution 11 - C++Dhirendra SengarView Answer on Stackoverflow