8

Quite new to C++. I have seen people usually pass objects by reference in operator overloading. Well, I can't figure out when it is really necessary. As in the code below, if I remove ampersand in declaration of object c1 and c2 in operator+, still I'll get the same result. Is there any reason to pass-by-reference in this case when we do not want to modify c1 or c2?

#include <iostream>

class Keys
{
private:
    int m_nKeys;

public:
    Keys(int nKeys) { m_nKeys = nKeys; }

    friend Keys operator+(const Keys &c1, const Keys &c2);

    int GetKeys() { return m_nKeys; }
};


Keys operator+(const Keys &c1, const Keys &c2)
{
    return Keys(c1.m_nKeys + c2.m_nKeys);
}

int main()
{
    Keys cKeys1(6);
    Keys cKeys2(8);
    Keys cKeysSum = cKeys1 + cKeys2;
    std::cout << "There are " << cKeysSum.GetKeys() << " Keys." << std::endl;
    system("PAUSE");
    return 0;
}
QuestionMark
  • 412
  • 1
  • 4
  • 16
  • If you don't pass objects by reference (or by pointer) as parameters, you pass them by values, which means they are copied; some objects can be expensive to copy. – piwi Oct 08 '14 at 07:40
  • Well you remove the need to copy the objects as params for one thing if you take a reference so it potentially will be more efficient taking the params as references – EdChum Oct 08 '14 at 07:40

4 Answers4

10

Operators are just like ordinary functions, just with "fancy" names :)
(e.g. operator+() instead of sum())

So, the same parameter passing rules that you apply to functions, can be applied to overloaded operators as well.

In particular, when you have a parameter that is not cheap to copy (e.g. an int, a float, are examples of cheap to copy parameters; a std::vector, a std::string, are examples of not cheap to copy parameters), and you observe this parameter inside your method (i.e. it's an input read-only parameter), then you can pass it by const reference (const &).

In this way, basically it's just like the address of the original argument is passed to the function, so there is no deep-copy involved. Deep-copies can be very expensive, e.g. think of a vector with a big number of elements.

So, to recap, you pass by const reference when:

  1. the parameter just is not cheap to copy (e.g. for ints, float, etc. just don't bother: passing by value is just fine)
  2. the parameter is observed in the function/operator implementation (i.e. it's an input read-only parameter)
Mr.C64
  • 41,637
  • 14
  • 86
  • 162
  • @ Mr.C64 Now in `ostream& operator<< (ostream &out, Something) { out << Something << endl; return out; }` what does the & after ostream do? – QuestionMark Oct 08 '14 at 17:55
  • @Farzin: That `&` is used since `out` is a _modifiable_ parameter, it's _not_ a read-only input parameter. Basically, `out` is a reference to a stream to which you append your own text. This operation _modifies_ the stream object, so you cannot pass it by `const` reference, you must drop the const. – Mr.C64 Oct 09 '14 at 09:32
  • @ Mr.C64: I meant the `&` in `ostream& operator`. – QuestionMark Oct 09 '14 at 13:46
  • @Farzin: You mean in the return value? That's because you are returning _the same_ `ostream` that was passed as input. If you returned by value (i.e. `ostream` without the `&`), then it would be _a copy_, **not the original input one**. – Mr.C64 Oct 09 '14 at 18:33
  • 1
    Thank you for this! Your terminology of "cheap"ness makes it easier to understand why one should pass by reference. – Aleksandr Hovhannisyan Aug 27 '17 at 22:27
3

If you pass by reference then there is no copy of the object made, which for more complicated classes could greatly improve performance.

In this case the performance cost may be marginal, and it's conceivable the compiler could optimise it all out, but it's still worth doing. Later the Keys class may change into something more complex.

David Sykes
  • 48,469
  • 17
  • 71
  • 80
1

Advantages of passing by reference:

  1. It allows us to have the function change the value of the argument, which is sometimes useful.
  2. Because a copy of the argument is not made, it is fast, even when used with large structs or classes.
  3. We can pass by const reference to avoid unintentional changes.
  4. We can return multiple values from a function.

Disadvantages of passing by reference:

  1. Because a non-const reference can not be made to a literal or an expression, reference arguments must be normal variables.
  2. It can be hard to tell whether a parameter passed by reference is meant to be input, output, or both.
  3. It’s impossible to tell from the function call that the argument may change. An argument passed by value and passed by reference looks the same. We can only tell whether an argument is passed by value or reference by looking at the function declaration. This can lead to situations where the programmer does not realize a function will change the value of the argument.
  4. Because references are typically implemented by C++ using pointers, and dereferencing a pointer is slower than accessing it directly, accessing values passed by reference is slower than accessing values passed by value.

You can read the below:

http://www.cs.fsu.edu/~myers/c++/notes/references.html

iampranabroy
  • 1,716
  • 1
  • 15
  • 11
0

Consider a vector of long having 10 million entries in it. If you prototype a function like:

void foo(vector<long> vl)
{
}

It will cause assignment-operator (or copy-constructor) of vector<long> - and that would need to copy all those 10m elements. Later destructor for this temporary object (vl) would de-allocate memory and perform other cleanup. It will definitely impact performance

There are classes, specially around synchronization providers (critical sections etc.), and some smart pointer classes that prevent copy-constructor and/or assignment-operators - so that assignment or object creation doesn't happen by mistake. Though move-constructor or move-assignment-operator may be implemented.

Ajay
  • 18,086
  • 12
  • 59
  • 105