c++ operator += overloading return reference to - c++

Could somebody explain what the difference is in this example of operator overloading, Average& operator+=(int num) where you return a reference to Average versus not returning a reference to Average i.e. Average operator+=(int num).
Does returning a reference mean return a reference to the object being assigned to (not a copy) which is *this. So in this case return a reference to the object avg.
How/why does the non reference version work? Where is the result being copied?
#include <iostream>
#include <cstdint> // for fixed width integers
class Average
{
private:
int32_t m_total = 0; // the sum of all numbers we've seen so far
int8_t m_numbers = 0; // the count of numbers we've seen so far
public:
Average()
{
}
friend std::ostream& operator<<(std::ostream &out, const Average &average)
{
// Our average is the sum of the numbers we've seen divided by the count of the numbers we've seen
// We need to remember to do a floating point division here, not an integer division
out << static_cast<double>(average.m_total) / average.m_numbers;
return out;
}
// Because operator+= modifies its left operand, we'll write it as a member
Average& operator+=(int num)
{
// Increment our total by the new number
m_total += num;
// And increase the count by 1
++m_numbers;
// return *this in case someone wants to chain +='s together
return *this;
}
};
int main()
{
Average avg;
avg += 4;
std::cout << avg << '\n';
return 0;
}

You should return a reference because thats a convention most code in standard library is using, and most programmers do. Most programmers will expect below code:
std::string s;
(s += "a") = "b";
std::cout << s << std::endl;
to print b, or in this example:
int n = 10;
(n += 20) = 100;
std::cout << n << std::endl;
will expect 100 to be printed.
That is why you should return a reference to keep with the convention which allows to modify object which is on the left side of assignment.
Otherwise, if you return by value (a copy) assignment as in above examples will assign to a temporary.

When overriding operators in C++, one can provide them in multiple forms. You can define assignment operators which do not return a reference to the modified object, and they would work as expected. But, we have for each operator what we call a canonical implementation:
Other than the restrictions above, the language puts no other constraints on what the overloaded operators do, or on the return type (it does not participate in overload resolution), but in general, overloaded operators are expected to behave as similar as possible to the built-in operators: operator+ is expected to add, rather than multiply its arguments, operator= is expected to assign, etc. The related operators are expected to behave similarly (operator+ and operator+= do the same addition-like operation). The return types are limited by the expressions in which the operator is expected to be used: for example, assignment operators return by reference to make it possible to write a = b = c = d, because the built-in operators allow that.
Commonly overloaded operators have the following typical, canonical forms.
There is a lot to read about those canonical forms, but I'd suggest to start with this really good SO answer on What are the basic rules and idioms for operator overloading?
How/why does the non reference version work?
Because even if the C++ Standard encourages you to use the canonical forms, it doesn't forbid you not to.
Where is the result being copied?
Nowhere, the value is discarded. Implementation will probably optimize them away.

Does returning a reference mean return a reference to the object being assigned to (not a copy) which is *this. So in this case return a reference to the object avg.
Yes.
How/why does the non reference version work? Where is the result being copied?
The returned value is a temporary object that is passed to std::cout <<.
It's similar to using:
int foo()
{
return 10;
}
std::cout << foo() << std::endl;
The return value of foo is a temporary object that is passed to std::cout <<.

Try to check this similar question.
When you return reference, you are actually passing the actual object. While when you return by value, temporary object is created and then passed to caller.
So if you return without reference this assignment may work as per your code segment above.
Average aa = avg += 4;
But it will fail to compile if you try.
Average *ptr = &(avg += 4);
The above code will work if you return reference though, since we are passing valid scope of object.

Related

Why do we return the object by reference when overloading << operator and not on overloading = and + operator? [duplicate]

This question already has answers here:
What are the basic rules and idioms for operator overloading?
(8 answers)
Closed 2 years ago.
I tried to consult the book and the reason I found there is that the prototype of the operator function to overload << operator is:
friend ostream& operator<<(ostream&, const className&);
Now consider the following statement:
cout << myRectangle << yourRectangle;
This statement is equivalent to the statement:
operator<<(operator<<(cout, myRectangle), yourRectangle); //Line A
because the associativity of the operator << is from left to right.
To execute the previous statement, you must first execute the expression:
cout << myRectangle
that is, the expression:
operator<<(cout, myRectangle)
After executing this expression, which outputs the value of myRectangle, whatever is
returned by the function operator << will become the left-side parameter of the
operator << (that is, the first parameter of the function operator<<) in order to output
the value of object yourRectangle (see the statement in Line A). The left-side
parameter of the operator << must be an object of the ostream type, so the expression:
cout << myRectangle
must return the object cout (not its value) to the left side of the second operator << in
order to output the value of yourRectangle.
Therefore, the return type of the function operator<< must be a reference to an object
of the ostream type.
That means you cannot pass an object by value as an argument where the formal parameter takes it by reference. So it makes sense to me why do we return by reference when overloading << operator. But where I get confused is in this statement:
tempRectangle = myRectangle + yourRectangle + anyRectangle;
According to the precedence and associativity of the operators, the compiler will first execute:
myRectangle + yourRectangle
Which is equivalent to:
myRectangle.operator+ (yourRectangle); // Line B
► Here comes my first confusion that after executing line B, it will return the object by value (which is then to be added by the third object, i.e. anyRectangle). So how do you write this addition in terms of line B (because we do not have any name to that object which is returned by value, so how does it perform this addition).
► Second confusion is that after adding all the three objects in this statement:
tempRectangle = myRectangle + yourRectangle + anyRectangle;
we have a returned-by-value object, which is then to be passed to operator= function to assign it tempRectangle. Now this is the same case as it happened it << operator. As the prototype of operator= function is :
className operator+(const className&) const;
This function also has a reference parameter. But we passing object by value as an actual parameter (in overloading << operator, we were having return by reference because we had to pass it to reference parameter which could not return by value object so why are we not doing the same here, i.e return by reference).
As mentioned in a comment operator= should return a reference. On the other hand operator+ is different because in
auto c = a + b;
The operator+ typically leaves both operands unchanged und a new object is created as result. For example
struct foo {
int value;
foo operator+(const foo& other) const {
foo result;
result.value = value + other.value;
return result;
}
};
If you chain operator+ as in
auto c = (a + b) + c;
Then operator+(c) is neither called on a nor b but on the result of a+b.

Assignment Operator Overloading in C++ Syntax Explanation

I am new to C++. I need some help understanding this code snippet.
Queue & operator=(const Queue &rhs)
{
front = rhs.front;
nWaiting = rhs.nWaiting;
for (int i = front, j = 0; j < nWaiting; j++)
{
elements[i] = rhs.elements[i];
i = (i + 1) % 100;
}
return *this;
}
I am unable to understand why there is an '&' before operator in the code and how does this work along with *this.
I understand operator overloading. For eg. the code below for addition operation overloading. However I don't understand why '&' is required for assignment operator (=) overloading.
V3 operator* (const double factor, const V3 &b)
{
return (b * factor);
}
The reference means that avoid copying the object. As a result, it will return a reference to the same object. Moreover, it will provide lvalue as a result. And if you think about it, that's what you want to happen when the assignment operator is used.
Every object in C++ has access to its own address through this pointer.
That means that the you return the object itself.
If your question is why we use *this instead of this, then this happens because you need to dereference the pointer first, since the return type is a reference (and not a pointer for example).
The & means the operator returns a reference (the original object), instead of a value (a copy of the object). This avoids unnecessary copying. this is a pointer to the object itself which the operator is called on, so return *this means return a reference to the object on the left side of the =.
This allows for the operator to be chained, like a = b = 1. This assigns 1 to b first, and a reference to b is returned. The value of b then gets assigned to a. So a and b both are 1.
The operator could be fine without any return value, however it is common to enable chaining as in
c = (a = b);
This will assign b to a and then assign the return value of the operator= call to c. As you dont want to make a unneccesary copy you return a reference to the object itself aka *this. Actually avoiding a copy is not the only reason for using a reference, but if you consider
(d = e) = f;
then this will only work as expected (first assigning e to d and then assigning f to d) if operator= returns a non-const (!) reference.
Note that operator* is different, because it is not supposed to modify the object it is invoked on but rather it returns a new instance (hence no & in the return of operator*).

C++ generic rvalue overload

I'm currently trying to refactor some code which uses a primitive type into something which I can tuck setters and getters into them. I wanted to make the change to the underlying code transparent, and at first I though C++'s operator overloads would help me out there.
Let's suppose I want to make an "augmented int" type, for instance, that can be treated just like a regular int, but allows for further action wherever I assign to it, and just assignment - all other properties of an int, such as adding with +=, should be preserved.
At first I first though that if I encapsulated the int inside some struct, and filled out the operator= overloads, I'd be set, like in the following example:
#include<iostream>
typedef struct PowerInt{
int x;
PowerInt(){
cout << "PowerInt created\n";
x = 0;
}
~PowerInt(){
cout << "PowerInt destroyed\n";
}
void operator=(int other){
cout << "PowerInt received " << other << "\n";
this->x = other;
}
}PowerInt;
int main(){
PowerInt a;
a = 3;
return 0;
}
The code compiles and runs as expected, but as soon as I try making anything else a regular int could do, like cout << a, or a += 2, or even a simple int b = a; assignment the compiler complains about the operators << and += missing.
Fair enough; I then though that, at least for << and "assigment =", I could get by using some sort of "generic rvalue operator", or some kind of method which returns PowerInt.x wherever my a is used as an rvalue, automatically making expressions like int c = (a + 3); and if (a == 3) {} valid.
Problem is, I can't find a way to implement this idiom, and this mostly likely has to do with either my little understanding of how operator overloading works in C++, or some language feature I'm not yet aware of. Is it possible to accomplish what I'm trying here?
If you want your PowerInt to be convertible to a normal int you can create a user-defined conversion operator:
operator int() const
{
return x;
}
Any operator that's not defined for PowerInt will then use the operator defined for a normal int.
P.S The typedef struct isn't necessary in C++.

Relevance of const return type in NRVO cases

This is a follow up question from Calling constructor in return statement.
This a operator overload fun in a class.
const Integer operator+(const Integer& IntObject)
{
cout << "Data : " << this->data << endl;
return Integer(this->data + IntObject.data);
}
What is the relevance of const in the return type for such functions?
int main()
{
Integer A(1); //Create 2 object of class Integer
Integer B(2);
const Integer C = A + B; //This will work
Integer D = A + B; //This will also work
fun(A + B); //Will work
}
void fun(Integer F) {}
This is a case temporaries are not created during return step due to NRVO. The object to be returned is directly constructed on the callee's address.
Here's a better example:
struct Foo
{
void gizmo();
Foo const operator+(Foo const & rhs);
};
Now if you have a Foo x; Foo y;, then you cannot say:
(x + y).gizmo(); // error!
The constant return value means you cannot use it for non-constant operations. For primitive types this is not quite so relevant, because there aren't many non-constant operations you can perform on temporary objects, because lots of "interesting" operations (like prefix-++) aren't allowed on temporaries.
That said, with C++11 one should really try and adopt the new idiom of never returning constant values, since non-constant values are now amenable to move optimisations.
Some people used to suggest doing that, to prevent writing nonsense like A + B = C. However, in C++11 it can prevent some optimisations since it makes the return value unmovable. Therefore, you shouldn't do it.
In this case, it also prevents you from writing perfectly valid code like D = A + B + C, but that's just because the author forgot to declare the operator const.
There is no relevance in your code snippet, because you are making a copy of the returned value.
In general, it is difficult to find good reasons to return a const value. I can only see it having an effect in this type of expression, attempting to call a non-const method on a const temporary:
(someObject.someMethodReturningConstValue()).someNonConstMethod(); // error, calls non const method on const temporary
so you should only use it if you want to disallow calling non-const methods on temporaries. On the other hand, it kills move-semantics in C++11 so is discouraged.

Function should return reference or object?

Let's discuss these two functions:
complex& operator+=(const T& val);
complex operator+(const T& val);
Where "complex" is a name of a class that implements for example complex variable.
So first operator returnes reference in order to be possible to write a+=b+=c ( which is equivalent to b=b+c; a=a+b;).
Second operator returnes and objec(NOT A REFERENCE), be we still able to write a=b+c+d.
Who could explain me this nuance? What is the difference between returning reference or object?
The assignment operators support multiple application to the same object:
(a += b) += c;
Which will add both b and c to a. For this to work, a += b must return a reference to a. The addition operator, however, doesn't require this, since the expression b + c + d has no side-effect. Only the final assignment to a has a side-effect.
In 1, a+=b, the += operator modifies a. Therefore it can return a reference to itself, because a itself is the correct result of the operation.
However, in 2. a new object is required because a+b returns something that is not a, so returning a reference to a wouldn't be correct.
The nuance is in the examples you give, in a way.
From the + operator you expect to get back a different value from the two you started with: b+c is neither b nor c, it's something else. Thus we can't return references to either b or c ... and short of allocating a new object on the stack those will be the only two we have to work with. Thus we have to return a value.
And you've already explained yourself why the += operator returns what it does.
Because complex& operator+=(const T& val); operates on this and because complex operator+(const T& val); must create a new temporary object for the sum.
If you were to return an object from +=, it would probably do what you expect, but there might be some extra copies in there. As you mentioned, you would want this behavior if you want to chain calls. If you returned a temporary and wrote (a += b) += c, your addition of c would be lost when it's destroyed in the temporary.
If you were to return a reference from +, you'd have a reference to a temporary and your program would have undefined behavior. You can write a=b+c+d because b+c creates a temporary b1 and b1 + d creates a temporary b2, which is then assigned to a.
In the first case, you are adding something to the object on the left, but the value of the expression is the object on the left. So you are returning something (usually the left) by reference. For example:
cout << (a+=b)
In the second case, you are adding two objects and getting a third object, and you can do this calculation on the stack, so you are returning an actual object by value rather than by reference.
For example:
if(...)
{
T a = b + c;
cout << a;
}