Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I write both copy and move assignment operators for a class?

These are my prototypes,

MyClass& operator=(MyClass rhs);   // copy assignment
MyClass& operator=(MyClass &&rhs); // move assignment

But when I call

MyClass a, b;
a = std::move(b);

, there is an error.

556 IntelliSense: more than one operator "=" matches these operands:
        function "MyClass::operator=(MyClass rhs)"
        function "MyClass::operator=(MyClass &&rhs)"
        operand types are: MyClass = MyClass    

And the compiler returns:

Error   56  error C2593: 'operator =' is ambiguous  
like image 297
ZHOU Avatar asked Apr 17 '15 12:04

ZHOU


People also ask

How to avoid copy when using copy assignment operator?

In the copy assignment operator, other can be constructor using a copy constructor or a move constructor (if other is initialized with an rvalue, it could be move-constructed --if move-constructor defined--). If it is copy-constructed, we will be doing 1 copy and that copy can't be avoided.

What is the difference between move assignment and copy assignment?

The move assignment operator takes an r-value reference only e.g. In the copy assignment operator, other can be constructor using a copy constructor or a move constructor (if other is initialized with an rvalue, it could be move-constructed --if move-constructor defined--).

Can a class have multiple move assignment operators?

A class can have multiple move assignment operators, e.g. both T& T::operator=(const T&&) and T& T::operator=(T&&). If some user-defined move assignment operators are present, the user may still force the generation of the implicitly declared move assignment operator with the keyword default.

Can subobjects be assigned more than once by the move operator?

It is unspecified whether virtual base class subobjects that are accessible through more than one path in the inheritance lattice, are assigned more than once by the implicitly-defined move assignment operator (same applies to copy assignment).


1 Answers

Overload resolution is ambiguous because when you pass an rvalue, both MyClass and MyClass && can be directly initialised by it.

If you want to provide a different implementation of copy and move assignment, the customary way is to take the copy assignment operator's parameter by const reference:

MyClass& operator=(const MyClass &rhs);   // copy assignment
MyClass& operator=(MyClass &&rhs); // move assignment

Done like this, the move assignment operator is a strictly better match for a (non-const) rvalue argument and so it's chosen by overload resolution.

An alternative approach, called copy-and-swap, is to provide just the assignment operator, take the parameter by value, and use swap to implement it:

MyClass& operator=(MyClass rhs)
{
  swap(*this, rhs);
  return *this;
};

This reuses the copy/move constructor for the assignment. It requires you to have implemented a swap function, which should be non-throwing.

The downside of this approach is that sometimes, manually implementing copy assignment can be cheaper than performing copy construction followed by a move.

like image 85
Angew is no longer proud of SO Avatar answered Sep 26 '22 21:09

Angew is no longer proud of SO