64

From what I understand: when you pass by value, the function makes a local copy of the passed argument and uses that; when the function ends, it goes out of scope. When you pass by const reference, the function uses a reference to the passed argument that can't be modified. I don't understand, however, why one would choose one over the other, except in a situation where an argument needs to be modified and returned. If you had a void function where nothing is getting returned, why choose one over the other?

EDIT: So basically passing by const reference avoids copying the object. So in what situations is copying the object good? I mean, why not just use const references all the time if it optimizes performance all the time?

Maulrus
  • 1,787
  • 2
  • 17
  • 27
  • 1
    possible duplicate of http://stackoverflow.com/questions/1567138/const-t-arg-vs-t-arg – Kirill V. Lyadvinsky Apr 06 '10 at 05:34
  • The article gf links covers your second question. In short: if you need a copy, then pass one. – Dennis Zickefoose Apr 06 '10 at 05:35
  • @Kirill Ah, that does answer my question. I searched for "pass by const reference" and it didn't turn anything up, so I missed that one. – Maulrus Apr 06 '10 at 05:40
  • Your statement about "where an argument needs to be modified" doesn't make sense when you're asking about *const* references. – jamesdlin Apr 06 '10 at 05:59
  • Why not? I'm saying that I didn't understand the difference between passing by value or by const reference in a situation EXCEPT for when the value would need to be modified and returned, which is then obviously a job for pass by value. – Maulrus Apr 06 '10 at 06:17
  • @Maulrus, or for non-const references. – Georg Fritzsche Apr 06 '10 at 06:45

8 Answers8

63

There are two main considerations. One is the expense of copying the passed object and the second is the assumptions that the compiler can make when the object is a a local object.

E.g. In the first form, in the body of f it cannot be assumed that a and b don't reference the same object; so the value of a must be re-read after any write to b, just in case. In the second form, a cannot be changed via a write to b, as it is local to the function, so these re-reads are unnecessary.

void f(const Obj& a, Obj& b)
{
    // a and b could reference the same object
}

void f(Obj a, Obj& b)
{
    // a is local, b cannot be a reference to a
}

E.g.: In the first example, the compiler may be able to assume that the value of a local object doesn't change when an unrelated call is made. Without information about h, the compiler may not know whether an object that that function has a reference to (via a reference parameter) isn't changed by h. For example, that object might be part of a global state which is modified by h.

void g(const Obj& a)
{
    // ...
    h(); // the value of a might change
    // ...
}

void g(Obj a)
{
    // ...
    h(); // the value of a is unlikely to change
    // ...
}

Unfortunately, this example isn't cast iron. It is possible to write a class that, say, adds a pointer to itself to a global state object in its constructor, so that even a local object of class type might be altered by a global function call. Despite this, there are still potentially more opportunities for valid optimizations for local objects as they can't be aliased directly by references passed in, or other pre-existing objects.

Passing a parameter by const reference should be chosen where the semantics of references are actually required, or as a performance improvement only if the cost of potential aliasing would be outweighed by the expense of copying the parameter.

Stumbler
  • 2,056
  • 7
  • 35
  • 61
CB Bailey
  • 755,051
  • 104
  • 632
  • 656
26

Passing arguments by value and thus copying them can be expensive - const references avoid that expensive step while still promising the caller that the object won't be changed.

Usually fundamental types (int, double, ...) are passed by value, while class-types are passed by const reference.

There can however be exceptions where pass-by-value for class-types can be beneficial.

GManNickG
  • 494,350
  • 52
  • 494
  • 543
Georg Fritzsche
  • 97,545
  • 26
  • 194
  • 236
7

Making a copy of an object could greatly affect the performance in some cases. Consider a function which argument will be std::vector<long> and you want to pass vector with 1 million elements. In this case you'll want to use const reference over passing by value. In this SO question you could find simple general rule for your question.

Community
  • 1
  • 1
Kirill V. Lyadvinsky
  • 97,037
  • 24
  • 136
  • 212
3

Sometimes, making a copy of an object can be expensive and so pass-by-const-reference will avoid having to make that copy. Otherwise, I would say that you should simply pass-by-value if that is what is semantically required.

Dean Harding
  • 71,468
  • 13
  • 145
  • 180
3

To avoid making an unnecessary copy, thus improving performance.

Paolo Tedesco
  • 55,237
  • 33
  • 144
  • 193
3

Passing an argument by value has the overhead of a copy of the object being passed to the function.

Maybe an object isn't copyable and your choices are limited.

pmr
  • 58,701
  • 10
  • 113
  • 156
3

Because of the performance benefits you will get. Lets say you have a big object (in terms of size in bytes). Now, if you pass this object by value to a function a unnecessary copy needs to be created of this, however you can get the same effect by passing a const reference to that object itself without creating copy. Since a reference is normally stored as a pointer under the hoods, the cost of passing a reference is just sizeof(pointer).

Naveen
  • 74,600
  • 47
  • 176
  • 233
  • I think during the copying, it doesn't copy the whole object right? It copies the reference to that object. Of course this would still have more overhead than passing the reference (and that there's no need to check for null pointers etc) But I don't think the size of the object matters in this copying. – kovac Mar 16 '19 at 08:57
  • @swdon: When you pass-by-value *whole* object is copied. So size does matter. – Naveen Mar 17 '19 at 07:08
2

An array can't be passed by value, so this is a good time to use a const pointer.

Baum mit Augen
  • 49,044
  • 25
  • 144
  • 182
Dovi Salomon
  • 159
  • 1
  • 5