-1

It looks like a time-saver sometimes if I can call the move assignment op from the move ctor. But when I try, it takes me straight to conventional assignment:

#include <iostream>
using namespace std;

class MyClass
{
public:
    MyClass() { }
    MyClass(const MyClass& other) { /* do some stuff */ }
    MyClass(MyClass&&      other);                  //move ctor

    const MyClass& operator= (const MyClass& other);
    const MyClass& operator= (MyClass&&      other); //move =
};

MyClass::MyClass(MyClass&& other)                   //move ctor
{
    cout << "Calling move ctor\n";
    *this = other; //<<--THIS IS THE PROBLEM
}

const MyClass& MyClass::operator= (MyClass&& other) //move =
{
    cout << "Calling move =\n";
    return *this;
}

const MyClass& MyClass::operator= (const MyClass& other)
{
    cout << "Calling standard =\n";
    if (this == &other) return *this;
    return *this;
}

MyClass makeVectorToTestMoveCtor() { MyClass V; return V; }

int main ()
{
    MyClass V = makeVectorToTestMoveCtor();

    return 0;
}

I can force it with std::move:

    cout << "Calling move ctor\n";
    *this = std::move(other); 

...but if it's not a bad idea, surely I shouldn't need to force it? What should I do here?

Topological Sort
  • 2,733
  • 2
  • 27
  • 54

2 Answers2

0

This is a bad idea - assignment's semantics are about mutating the state of an existing object to make it match another one. A constructor exists to initialize an object that previously didn't exist.

Furthermore, you cannot initialize members with the member initialization list, which requires your data members to be default-constructible and non-const.

If anything, it would make more sense to define the assignment in terms of the constructor, something like:

foo& foo::operator=(foo&& rhs)
{
    this->~foo();
    new (this) foo{std::move(rhs};
}

For the above snippet, you need to be careful to not trigger UB, though: Placement new and assignment of class with const member


In general, I would just define both operators separately unless you can let the compiler generate them for you.

Vittorio Romeo
  • 90,666
  • 33
  • 258
  • 416
  • Don't do that (destroy then construct). It isn't exception safe. It may also be broken when doing self-assignment. – Nevin Jun 28 '19 at 00:50
  • @Nevin: I am not advocating for that, I am saying that it would make more sense to define assignment in terms of constructor rather than the other way around. The link I posted shows that the destroy+placement new is indeed dangerous. My last sentence advocates for manual definition of both functions, or following the rule of zero – Vittorio Romeo Jun 28 '19 at 08:50
0

Construction is the more fundamental operation. You have to have a constructed object before you can assign to or from it. Write your assignment in terms of construction and not the other way around.

Nevin
  • 4,595
  • 18
  • 24