15

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?".)

Cœur
  • 37,241
  • 25
  • 195
  • 267
Roddy
  • 66,617
  • 42
  • 165
  • 277
  • 2
    What about every time you need a copy anyway? Add `Obj o2(o);` as first line? That seems rather pointless. Also, move semantics. –  Aug 10 '12 at 16:02
  • @delnan - Thanks. I usually do as you describe, as I think that's an implementation detail of the function that shouldn't form part of it's external signature. – Roddy Aug 10 '12 at 16:06
  • @Nemo. Yes, thanks. Voted to close! Sadly the hive mind is a better search tool than SO's built-in one... – Roddy Aug 10 '12 at 16:20
  • @Roddy: No worries. It is definitely becoming harder to find old answers on SO, unfortunately. – Nemo Aug 10 '12 at 16:23
  • @Roddy: You mean you take by reference then copy within the function on the first line? – GManNickG Aug 10 '12 at 16:34
  • @GManNickG - Exactly. Although I now see reasons why that might not be ideal. But on compiler I'm currently using the optimization issues are largely irrelevant. – Roddy Aug 10 '12 at 16:55
  • *"are compilers allowed to automatically convert the call to (and from) a const reference if appropriate?"* -- If the observable behavior is exactly the same either way, the compiler is free to make any changes it wants. – Benjamin Lindley Aug 10 '12 at 17:08

6 Answers6

10

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:

  • Because Obj fits in a register and passing by value and passing by value will be more efficient

Still 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),

  • if the function needs to make a copy, then doing so in the interface allows the compiler to perform copy-elision if the source for the copy is a temporary, so it can be more efficient.

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

  • if the function needs to make a copy, even when the copy cannot be elided, and for types that support it, the contents will be moved (in common jargon the object will be moved, but it is only the contents that get shifted), which again will be more efficient than copying internally.

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).

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
6

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.

Mark B
  • 95,107
  • 10
  • 109
  • 188
4

If I wanted to do things to the object within the function without affecting the original, I would pass by value:

A minus(A b){
    b.val=-b.val;
    return b;
}
Gir
  • 839
  • 5
  • 11
3

The copy swap idiom uses passe by value to achieve a compiler generated copy.

MyClass& operator=(MyClass value) // pass by value to generate copy
{
    value.swap(*this);            // Now do the swap part.
    return *this;
}

Basically in situations where you will need to modify the parameter but do not want to touch the original. In these situations if you pass by const reference you manually need to create a copy inside the function. This manual steps will prevent certain optimizations that the compiler can perform if you let the compiler handle the copy.

MyClass a;
// Some code
a = MyClass(); // reset the value of a
               // compiler can easily elide this copy.
Roddy
  • 66,617
  • 42
  • 165
  • 277
Martin York
  • 257,169
  • 86
  • 333
  • 562
1

If the object is mutable, passing by value gives the receiver its own copy to use and where sensible change, without affecting the caller's copy - always assuming it's a sufficiently deep copy.

This may simplify thinking in some multi-threaded situations.

djna
  • 54,992
  • 14
  • 74
  • 117
1

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?

Let me answer the second one first: sometimes.

Compilers are allowed to elide the copy into the parameter, but only if you pass in an rvalue temporary. For example:

void foo(Obj o);

foo((Obj()))); //Extra set of parenthesis are needed to prevent Most Vexing Parse

The copying of the temporary into the argument parameter may be elided (ie: not copied), at the compiler's convenience).

However, this copy will never be elided:

Obj a;
foo(a);

Now, on to the first. C++ needs both because you may want to use both for different things. Pass by value is useful for transferring ownership; this is more important in C++11 where we can move rather than copy objects.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • Thanks. "Pass by value is useful for transferring ownership" Could you elaborate just a little? – Roddy Aug 10 '12 at 16:23