1

I see that in a lot of examples in c++ that operator overloading gets as an argument a class instance passed by reference or if it returns a class instance it returns it by reference as well. Is there any reason why people choose to pass it by reference while passing a pointer / by value will work as well ? An example :

Class MyClass
{
public:
    int m_num;
    MyClass() { m_num = 1;}
    const MyClass operator+(const MyClass& mcls)
    {
        MyClass temp;
        temp = m_num + mcls.m_num;
        return temp;
    }
}

Assume that we overload the = operator.

So taking for example the code I wrote, sending arguments to the operator+ overload function NOT by reference AND ALSO returning an instance of MyClass not by reference will work as well yet I see in a lot of examples it's passed and returned by reference and I would like to know if there's a reason behind this or it's just convention of some type or maybe a preference ?

Tugal.44
  • 153
  • 4
  • 13
  • Returning a const reference there isn't really good at all. Check the warning you should have. – chris Sep 26 '14 at 01:51
  • mind explaining what you're saying more in depth ? And also address my main question – Tugal.44 Sep 26 '14 at 01:53
  • @Tugal.44, http://coliru.stacked-crooked.com/a/824e82a5c9e1cf8c – chris Sep 26 '14 at 01:55
  • @chris sorry I didn't notice I did that, tried to shove this into my example without really paying attention to what I was doing, fixed. So about my main question, you think you could answer that ? Why sometimes when you pass people choose to pass by ref most of the time – Tugal.44 Sep 26 '14 at 01:57
  • Well, returning a const value disables moving the return value from the function in the case RVO can't do anything for it. If it's C++11, you can suffer from putting the `const` there. – chris Sep 26 '14 at 02:03
  • [See here](http://stackoverflow.com/questions/7360775/why-does-overloaded-assignment-operator-return-reference-to-class) for explanation of the return type – M.M Sep 26 '14 at 02:42
  • @MattMcNabb I see someone answered while((c = getchar()) != EOF) with this example, my brain can't process what's wrong with it if the =operator would return void, so c gets assigned and then being checked if it's != EOF – Tugal.44 Sep 26 '14 at 02:52
  • 1
    @Tugal44 `void` cannot be an operand of `!=`. It seems like you fundamentally don't understand how expressions work in C++. Every expression results in a value. When you have `(a + b) + c` for example, first the value is computed by `(a + b)`, and then the second step is that the result of that computation (which doesn't have a name) is added to `c`. – M.M Sep 26 '14 at 02:54
  • @MattMcNabb so the operators acts like functions returning a value ? and if it won't return a value you wouldn't be able to use a compound operator ? – Tugal.44 Sep 26 '14 at 02:56
  • @MattMcNabb Ok I think I've got it, thanks for sticking here trying to explain this :) – Tugal.44 Sep 26 '14 at 03:03

3 Answers3

1

If your actual question is about passing by const reference, then see Why pass by const reference instead of by value?, otherwise keep reading.


You shouldn't return a reference to a local variable. The local variable goes out of scope, leaving a reference to garbage. The C++ operator overloading guidelines state that operator+ shouldn't modify either operands and returns a new value from the two arguments.

const MyClass operator+(const MyClass& mcls) const
{
    MyClass temp = *this;
    temp.m_num += mcls.m_num;
    return temp;
}

For this reason, it is important you return a copy.

On the other hand, regarding operator=, you do want to return a reference because it is the copy assignment operator. For example:

  MyClass& MyClass::operator=(const MyClass &rhs) {
    // Check for self-assignment!
    if (this == &rhs)      // Same object?
      return *this;        // Yes, so skip assignment, and just return *this.

    ... // Deallocate, allocate new space, copy values...

    return *this;
  }

You want to copy rhs into *this and return a reference:

[...] to support safe and reasonable operator chaining. (Do this by returning *this.)

  • I'm having difficulties understanding why returning *this will allow chaining, dasblinkenlight explained the same thing to me and I've responded explaining what I don't understand, mind checking this ? – Tugal.44 Sep 26 '14 at 02:27
1

If your function were:

MyClass operator+(const MyClass *mcls) 

then the code a + b would not compile. You'd have to write a + &b which is horrible.

It is valid to have the operator as:

MyClass operator+(MyClass mcls)

This code , conceptually, creates an extra copy of mcls because it is passed by value. If this copy can actually be moved out of, or elided or otherwize optimized out, then this is a good style. Otherwise, the const MyClass & version is a good optimization (sometimes a premature one!) to avoid this potential extra copy.

Note that both of these should be const (that is, the function - not the return value) since they do not modify *this. And it is considered better style for operator+ to be a non-member function

The reason that operator+ should not return a reference is that people expect that + takes two inputs and generates a new output. If the code is c = a + b; then we expect a to remain unchanged. You have to make a new object somewhere which holds the sum, and return that. When we return by value, this is a temporary object and usually the compiler will elide it and write the results directly into c.

It is correct for operator+= to modify *this and return a reference to *this. A good way of implementing operator+ is actually to just call operator+= on the first operand (when passed by value).

M.M
  • 138,810
  • 21
  • 208
  • 365
  • Why is it considered a better style for operator+ to be a non-member function ? I agree on making them const, forgot. Also why operator+= should return *this ? What's wrong with just modifying this members and be done with it, why the need of returning from += operator ? – Tugal.44 Sep 26 '14 at 02:14
  • If it is a non-member than you can write both `c = 3 + b;` and `c = a + 3;` if your class has any converting constructors from `int`. Also it's better for code modularity and encapsulation to separate your object's functionality from operations which are done on your object. – M.M Sep 26 '14 at 02:21
  • You could return `void` in `operator+=` but you may as well return `*this` to allow chaining, e.g. `func( a += b );` which means `a += b; func(a);`. The general idea in designing your overloaded operators is to make them behave as closely as possible to how the built-in operators behave for built-in types. Then people who use your operator do not have any unpleasant surprises in store for them. – M.M Sep 26 '14 at 02:22
  • I'm having difficulties understanding why returning *this will allow chaining, dasblinkenlight explained the same thing to me and I've responded explaining what I don't understand, mind checking this ? – Tugal.44 Sep 26 '14 at 02:26
  • @Tugal44 your question is really asking two separate questions: (a) why pass parameters by const reference, (b) why does operator+ return by value. You should have posted two separate questions (or consulted existing answers, probably there is already a question for each of those). If you want to include operator+= as well then that's another question. This should all be explained by whatever book or guide you are using to learn operator overloading. – M.M Sep 26 '14 at 02:33
  • unfortunately it doesn't explain it (for now, maybe it'll later) and I'm just asking about the operators return type because you guys decided to point me this as something I should note of – Tugal.44 Sep 26 '14 at 02:40
1

Strictly speaking, passing by reference or by constant reference is not required: the code would work with passing by value. However, for most operators that would be inefficient, because passing by value entails copying the entire object - something you avoid when you pass by reference.

Same goes for returning a value: more often than not, you should return by value. However, there is one notable exception to this rule: all compound assignment operators need to return by reference, because they return (*this).

Using pointers instead of references is out of the question, but for a different reason: C++ requires operators to be compatible with specific signatures by type; a reference is type-compatible with a value of the corresponding type, but a pointer is incompatible. If you define an overload of an operator that takes pointers, C++ would not use your operators when working with values.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • Regarding to your second assignment operator. Why should I return anything ? Won't returning void be good enough ? it's just assigning the values so why should I return *this ? – Tugal.44 Sep 26 '14 at 02:10
  • @Tugal.44 Because you can chain assignments and compound assignments, as in `a = b = c` or `a = b = c++` etc. – Sergey Kalinichenko Sep 26 '14 at 02:14
  • Why in chain assignments can't it act as if we were to write a = b = c so when doing b = c, b values changes and then a = b, a values changes, still don't understand how returning a ref is necessary ? – Tugal.44 Sep 26 '14 at 02:21
  • @Tugal.44, If `b = c` returns `void`, you've got `a = someVoidThing`. You can verify that yourself with a compiler. – chris Sep 26 '14 at 02:26
  • @Tugal.44 If assignment or compound assignment returned by value, the semantics of this would be wrong: `MyClass a; MyClass b; MyClass &c = a = b;` In the above code, `c` is supposed to be a reference to `a` itself, not to its copy. – Sergey Kalinichenko Sep 26 '14 at 02:29
  • @chris but the way I would've implemented operator= would be something like m_num = mcls.m_num; I'm not returning just assigning so if I chaning a = b = c, b = c, b changes and then a = b, a changes (assuming that is the order) even if that's not the order then it'll still assign the values the other direction – Tugal.44 Sep 26 '14 at 02:30
  • @Tugal44 `a=b=c;` means `a = (b = c);` . You seem to be tacitly assuming it means `b = c; a = b;` but it doesn't. – M.M Sep 26 '14 at 02:34
  • @dasblinkenlight so we return *this just in the case of when we could have a ref to an object ? but you said we should return *this in all compound assignments so what about operator+ ? it's compound yet there's no risk of what you just described as assigning ref to object values. – Tugal.44 Sep 26 '14 at 02:35
  • @MattMcNabb nonetheless I said what I think applies in any order, so if it goes from left to right then a = b = c, first a = b, a values will change then the other assignment – Tugal.44 Sep 26 '14 at 02:36
  • @Tugal44 You're making stuff up. `a = b = c;` means `a = (b = c);`, that's how C++ language is defined. – M.M Sep 26 '14 at 02:39
  • @Tugal.44 `+` is not compound, `+=` is. You can do this, too: `MyClass &c = a += b`, and `c` should become a reference to `a`. In general, you want to maintain semantics for your classes that matches semantics of built-in types. – Sergey Kalinichenko Sep 26 '14 at 02:40
  • @dasblinkenlight if I can do for example c = a + b + d does it count as a compound operation ? – Tugal.44 Sep 26 '14 at 02:42
  • @MattMcNabb if a = b = c is a = (b = c) how isn't it like b = c; a = b; ? Can't see how, mind explaining ? – Tugal.44 Sep 26 '14 at 02:42
  • @Tugal44 because that is what the definition of C++ is . – M.M Sep 26 '14 at 02:44
  • @MattMcNabb so what a = b = c actually means ? Because if it doesn't mean b = c; a = b; I can't understand what it means – Tugal.44 Sep 26 '14 at 02:45
  • It means `a = (b = c);`. I don't know any way to say this more clearly. The result of `b = c` is the return value of the `operator=` function. – M.M Sep 26 '14 at 02:51
  • @Tugal.44, Here's an example of them obviously acting differently. Notice how one compiles and the other doesn't: http://coliru.stacked-crooked.com/a/ee3e0daa448f5522. `b = c` is an expression, just like `b` is, and just like `c` is, and just like `2+5` is. The result of that expression is used for the chaining: `a = (b = c)` becomes `a = result`. It just happens to have a side effect, which is updating `b`'s value. – chris Sep 26 '14 at 03:22