Why Must the Copy Assignment Operator Return a Reference/Const Reference

Why must the copy assignment operator return a reference/const reference?

Strictly speaking, the result of a copy assignment operator doesn't need to return a reference, though to mimic the default behavior the C++ compiler uses, it should return a non-const reference to the object that is assigned to (an implicitly generated copy assignment operator will return a non-const reference - C++03: 12.8/10). I've seen a fair bit of code that returns void from copy assignment overloads, and I can't recall when that caused a serious problem. Returning void will prevent users from 'assignment chaining' (a = b = c;), and will prevent using the result of an assignment in a test expression, for example. While that kind of code is by no means unheard of, I also don't think it's particularly common - especially for non-primitive types (unless the interface for a class intends for these kinds of tests, such as for iostreams).

I'm not recommending that you do this, just pointing out that it's permitted and that it doesn't seem to cause a whole lot of problems.

These other SO questions are related (probably not quite dupes) that have information/opinions that might be of interest to you.

  • Has anyone found the need to declare the return parameter of a copy assignment operator const?
  • Overloading assignment operator in C++

C++ why the assignment operator should return a const ref in order to avoid (a=b)=c

(x=y) means x.operator=(y), which returns the object x. Therefore, (x=y)=z means (x.operator=(y)).operator=(z). The expression in parens sets x to y and returns x, and then the outer bit sets x to z. It does not set y to z as you might expect, and as the expression x = y = z does.

This behavior is counter-intuitive (they should all be equal after the assignment, right?); returning a const reference makes it impossible and avoids the problem.

Why not return const-reference in operator= instead of a reference?

You can, but the users of MyClass may be surprised.

Usually, references can be taken to assignments (and less often, assignments can be assigned again). This is slightly confusing to word correctly, so here's what it looks like:

int a = 4;
int &r = a = 5;
(a = 6) = 7;

This also disallows calling member functions that modify the arguments of the function, for example:

#include <iostream>

struct C
{
int value;
const C &operator=(int v){value = v; return *this;}
};

void assign_value(C &ref)
{
ref %= 4;
}

int main(void)
{
C test;
assign_value(test = 5);
std::cout << c.value << '\n';
}

Why GCC refuses a const reference within a copy-assignment operation?

or we can NOT delete it?

You just don't need to do that. If you provide a user-defined copy assignment operator, then no other ones will be implicitly-declared, i.e. only the user-defined one will exist.

If you do that, the copy assignment operator you explicitly marked as delete will participate in overload resolution; when it's selected the compilation fails. For ob = oa;, the operator=( ClassA & ) is a better match, if it doesn't exist, operator=( const ClassA & ) will be used and work fine.

So in this case you can just do

class ClassA {
public:

ClassA & operator=( ClassA && ) {
cout << "ClassA & operator=( ClassA && ) executed." << endl;
return *this;
}

ClassA & operator=( const ClassA & ) {
cout << "ClassA & operator=( const ClassA & ) executed." << endl;
return *this;
}
};

Why does operator = return *this?

You return *this so you can write normal compound C++ = statements like:

Poly p1; //an object representing a polynomial
Poly p2;
Poly p2;

// ...

p3 = p2 = p1; //assigns all the contents of p1 to p2 and then to p3

because that statement is basically:

p3.operator=(p2.operator=(p1));

If p2.operator=(...) didn't return *this you'd have nothing meaningful to pass into p3.operator=(...).

Why should the assignment operator return a reference to the object?

The usual form returns a reference to the target object to allow assignment chaining. Otherwise, it wouldn't be possible to do:

Foo a, b, c;
// ...
a = b = c;

Still, keep in mind that getting right the assigment operator is tougher than it might seem.

Should copy assignment operator pass by const reference or by value?

Prior to C++11, it has always been the case that copy assignment operator should always pass by const reference

That is not true. The best approach has always been to use the copy-and-swap idiom, and that's what you're seeing here (although the implementation in the body is sub-optimal).

If anything, this is less useful in C++11 now that you have a move assignment operator too.

why does builtin assignment return a non-const reference instead of a const reference in C++?

By design, one fundamental difference between C and C++ is that C is an lvalue-discarding language and C++ is an lvalue-preserving language.

Before C++98, Bjarne had added references to the language in order to make operator overloading possible. And references, in order to be useful, require that the lvalueness of expressions be preserved rather than discarded.

This idea of preserving the lvalueness wasn't really formalized though until C++98. In the discussions preceding the C++98 standard the fact that references required that the lvalueness of an expression be preserved was noted and formalized and that's when C++ made one major and purposeful break from C and became an lvalue preserving language.

C++ strives to preserve the "lvalueness" of any expression result as long as it is possible. It applies to all built-in operators, and it applies to built-in assignment operator as well. Of course, it is not done to enable writing expressions like (a = b) = c, since their behavior would be undefined (at least under the original C++ standard). But because of this property of C++ you can write code like

int a, b = 42;
int *p = &(a = b);

How useful it is is a different question, but again, this is just one consequence of lvalue-preserving design of C++ expressions.

As for why it is not a const lvalue... Frankly, I don't see why it should be. As any other lvalue-preserving built-in operator in C++ it just preserves whatever type is given to it.

Why we use reference return in assignment operator overloading and not at plus-minus ops?

Returning a reference from assignment allows chaining:

a = b = c;  // shorter than the equivalent "b = c; a = b;"

(This would also work (in most cases) if the operator returned a copy of the new value, but that's generally less efficient.)

We can't return a reference from arithmetic operations, since they produce a new value. The only (sensible) way to return a new value is to return it by value.

Returning a constant value, as your example does, prevents move semantics, so don't do that.



Related Topics



Leave a reply



Submit