Assignment Operator Overloading in C++ Syntax Explanation - c++

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

Related

Operator overloading C++ reference or value

I've seen many tutorials and tried to find the answer on stackoverflow but with no success.
What I'm not sure of is; is there some praxis when to return by value or by reference, when overloading an operator?
For e.g.
Class &operator+(){
Class obj;
//...
return obj;
}
or the same thing but by value
Class operator+(){
Class obj;
//...
return obj;
}
And I'd like to mention, I've noticed that in almost 90% of cases when returning the same object (*this), is being referenced on the same object returned. Could someone explain why is that so, as well?
The first option of returning from operator+ by by reference is wrong, because you are returning local object by reference, but the local object ceases to exist after the operator function body ends. Generally:
Mutating operators like += or -= return by reference, because they return the mutated object itself (by: return *this;)
Normal operators like + or - should return by value, because a new object needs to be constructed to hold the result.
... is there some praxis when to return by value or by reference, when overloading operator?
Yes, there are some canonical forms found here. They don't all have the same form - they vary by operator. The general advice is to follow the semantics of the built-in types. As with all functions, general rules still apply, such as not returning references to local variables (as shown in the OP).
E.g. (found in the link above) given the addition operator of the question;
class X
{
public:
X& operator+=(const X& rhs) // compound assignment (does not need to be a member,
{ // but often is, to modify the private members)
/* addition of rhs to *this takes place here */
return *this; // return the result by reference
}
// friends defined inside class body are inline and are hidden from non-ADL lookup
friend X operator+(X lhs, // passing lhs by value helps optimize chained a+b+c
const X& rhs) // otherwise, both parameters may be const references
{
lhs += rhs; // reuse compound assignment
return lhs; // return the result by value (uses move constructor)
}
};
The operator+ is a non-member method (often as a friend) and returns by value - this corresponds to the semantics of the built in types. Similarly, the operator+= is a member method and returns by reference (an updated version of *this).
... when returning the same object (*this), is being referenced on the same object returned. Could someone explain why is that so, as well?
If the return type is by-value (X operator+), then return *this; means that a copy of the current object (what is pointed to by this) is made and returned.
If the return type is by-reference (X& operator+), then return *this; means that a reference to the current object (what is pointed to by this) is returned (i.e. not a copy).

Handling Dangling pointer/reference in case of operator overloading

Is it safe to write our own copy constructor always during operator overloading ?
Complex Complex::operator+(const Complex& other)
{
Complex local ;
local.result_real = real + other.real;
local.result_imaginary = imag + other.imag;
return local ;
}
Most of the times i have seen the above format , instead of returning it as reference .
Can we take thumb rule like
1- Always pass the function parameter by reference .
2- Always return the object by reference .
Is there any special case in operator overloading where we have to return the object by value only ?
Can we take thumb rule like 1- Always pass the function parameter by reference . 2- Always return the object by reference .
No, not really. Even if you found a way to return a non-dangling reference, an operation such as addition should not return a reference, since this does not make sense. a+b should return a new object, while for a+=b it does make sense to return a reference to the LHS.
Concerning passing an argument by reference, there is no rule of thumb either. Consider this:
A operator+(const A& lhs, const A& rhs)
{
A tmp = lhs; // explicitly make a copy
return tmp += rhs;
}
and this:
A operator+(A lhs, const A& rhs)
{
return lhs += rhs;
}
The second version passes one argument by value, resulting in simpler code and giving the compiler more opportunities to elide temporary copies.
For some operators you should return a reference, for others you should not, and still others return other types completely (like the comparison operators).
In your case you should not. Especially since you will then return a reference to a local variable which will not be valid when the function returns.

Why does "return *this" return a reference?

In my C++ class they were discussing how to create an assignment operator. At the end of the assignment was the line "return *this," which they said returned a reference to the object that "this" points to. Why does it return a reference? If "this" is being dereferenced, shouldn't it just return the object?
A function returns a reference if its declaration (i.e. its signature) tells so.
So (assuming a class Foo) if a function is declarated
Foo fun();
then it returns a value (with copying, etc..)
But if it is declared as
Foo& fun();
or as
const Foo& fun();
a reference is returned.
The statement return *this; don't define by itself if a reference or a value is returned.
It returns the current instance of the type MyClass you are in. It's returned as reference because the assignment operator was explicitly told to return a reference.
MyClass& operator = (MyClass& other) { return *this; }
Note the & after MyClass as the return value. A reference is returned.
Unless the & weren't there right before operator, the instance would be returned by value.
The expression *this
At the end of the assignment was the line "return *this," which they said returned a reference to the object that "this" points to
They were wrong.
Why does it return a reference?
It doesn't.
If "this" is being dereferenced, shouldn't it just return the object?
Yes!
Dereferencing a pointer yields an lvalue. That means that the result of *this is the actual object that this points to. It's not a reference, but it's not a copy either.
[C++11: 5.3.1/1]: The unary * operator performs indirection: the expression to which it is applied shall be a pointer to an object type, or a pointer to a function type and the result is an lvalue referring to the object or function to which the expression points. If the type of the expression is “pointer to T,” the type of the result is “T.” [..]
It can be hard to conceptualise, since you can never do this yourself in code; it's just a feature of the * operator for native pointers, and has been since C.
Returning from operator=
Because you can't do it yourself, conventionally you'd bind that lvalue expression to a reference in order to use it in different contexts. For example, the expression *this in return *this gets bound to the return type of the function that you're returning from; in this case, an assignment operator.
Now, we could have the assignment operator return by value in which case an object copy would be made from the lvalue that comes from *this; however, for an assignment operator we usually return by reference so that we avoid an almost-certainly needless copy, and can perform chaining:
Type a, b, c;
c = b = a;
It's a convention with benefits, and no downsides. Can you think of a situation when you'd want op= to return by value?
Every dereferenced pointer is a reference to its pointee, else you'd 'loose' the pointee you're pointing to.
Invoke method twice on the same object, using a pointer and a reference:
MyClass* objPtr = .... ;
objPtr->doSomething();
MyClass& objRef = *objPtr;
objRef.doSomething();
Invoke method on distinct objects; original and copy:
MyClass* objPtr = .... ;
objPtr->doSomething();
MyClass objCopy = *objPtr; //here, the reference is passed to the (implicit or implemented) copy constructor if possible, else a compile time error occurs.
objCopy.doSomething();
That means, if you return a reference from an operator method which has MyClass (rvalue) instead of MyClass& (lvalue) as return type, a copy of *this (MyClass&) is created by reference (leaving aside return value optimizations and rvalue references).
This is useful for non modifying const methods such as + and - which have a new value as result while leaving the object on which this method was invoked unmodified.
Operators like += and your assignment operator modify the object inplace by convention and should therefore return a reference to allow expressions like primitive types support it, since a temporary copy may vanish and cause unexpected results:
Consider this expression:
int i = 4;
int r = (i += 3) <<= 2;
The result r is 28 (added and shifted inplace).
What is the value of i? 28 too, what else.
But what if hypothetically int::operator+= would return a copy of itself instead of a reference to itself?
The result r would be 28 too.
But the value of i?
It would be 7, since the inplace left shift was applied to a temporary int returned from the addition which gets assigned to r after that.
Continuing the assumption, the error may have the same effect (except for the value in i) as this expression:
int r = (i + 3) <<= 2;
But luckily, the compiler will complain, that he doesn't have an lvalue reference from (i + 3) to do the shift/assignment operation.
But play with this:
class Int
{
private:
int val;
public:
Int(int val) :
val(val)
{
}
Int operator+(const Int& other)const
{
return val + other.val;
}
Int operator+(int prim)const
{
return val + prim;
}
Int& operator+=(const Int& other)
{
val += other.val;
return *this;
}
//Error here, Int& would be correct
Int operator+=(int prim)
{
val += prim;
return *this;
}
Int operator<<(const Int& other)const
{
return val << other.val;
}
Int operator<<(int prim)const
{
return val << prim;
}
Int& operator<<=(const Int& other)
{
val <<= other.val;
return *this;
}
Int& operator<<=(int prim)
{
val <<= prim;
return *this;
}
operator int()const{
return val;
}
};
int main()
{
Int i = 4;
Int r = (i += 3) <<= 2;
cout << i;
return 0;
}
In C++ the * always means a value, in fact you can look to en English interpretation for these operators as follows:
&: the address of
*: the value of
So when you say &x it means "the address of x" and when you say *x it means "the value that x points to". So *this will always return a value.
Just be sure that the function itself that the hosts the returning is not a reference function. Please remember that in C++ you can create functions with the & or the * operators as well.

operator overloading

iarray<T>& operator = (iarray<T>& v)
Why the return type is iarray<T>& not iarray<T> ?
UPDATE
Can someone elaborate in great detail why iarray<T> const &v ?
Because you don't want to return a copy of the array just for the sake of chaining. Returning a reference is a better option as it doesn't result in a copy being constructed.
Because then you can chain them efficiently, eg.
a = b = c;
See the C++ FAQ.
Why the return type is iarray& not iarray ?
Because the result of an assignment is a reference to what just got assigned. For example, the result of a = b should be a reference to a so you can chain them together like in c = a = b; which is effectively a = b; c = a;. (Yes, people like doing this on rare occasions; no, I don't know why it's such a hardship to break it into two lines.) Thus your code should look like:
iarray<T>& iarray<T>::operator = (const iarray<T>& v)
{
// ... copy `v`'s state over this object's ...
return *this;
}
Can someone elaborate in great detail why iarray const &v ?
Because an assignment operation has no business changing the right-hand side; it is unexpected behavior. If you have some funky thing in your object that needs to change, like a reference count, then you should prefer declaring that one part mutable over disallowing const right-hand side expressions. You can pass a non-const value in for a const parameter, but the reverse is not true.

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;
}