20

For some time this has been confusing me. And I've not been able to find a satisfactory answer thus far. The question is simple. When does a move assignment operator get called, and when does a move constructor operator get called?

The code examples on cppreference.com yield the following interesting results:

The move assignment operator:

a2 = std::move(a1); // move-assignment from xvalue

The move constructor:

A a2 = std::move(a1); // move-construct from xvalue

So has it do to with which is implemented? And if so which is executed if both are implemented? And why is there the possibility of creating a move assignment operator overload at all, if it's identical anyway.

laurisvr
  • 2,724
  • 6
  • 25
  • 44

4 Answers4

25

A move constructor is executed only when you construct an object. A move assignment operator is executed on a previously constructed object. It is exactly the same scenario as in the copy case.

Foo foo = std::move(bar); // construction, invokes move constructor
foo = std::move(other); // assignment, invokes move assignment operator

If you don't declare them explicitly, the compiler generates them for you (with some exceptions, the list of which is too long to be posted here).

See this for a complete answer to when the move member functions are implicitly generated.

vsoftco
  • 55,410
  • 12
  • 139
  • 252
5

When does a move assignment operator get called

When you assign an rvalue to an object, as you do in your first example.

and when does a move constructor operator get called?

When you initialise an object using an rvalue, as you do in your second example. Although it isn't an operator.

So has it do to with which is implemented?

No, that determines whether it can be used, not when it might be used. For example, if there's no move constructor, then construction will use the copy constructor if that exists, and fail (with an error) otherwise.

And if so which is executed if both are implemented?

Assignment operator for assignment, constructor for initialisation.

And why is there the possibility of creating a move assignment operator overload at all, if it's identical anyway.

It isn't identical. It's invoked on an object that already exists; the constructor is invoked to initialise an object which previously didn't exist. They often have to do different things. For example, assignment might have to delete something, which won't exist during initialisation.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
4

This is the same as normal copy assignment and copy construction.

A a2 = std::move(a1);
A a2 = a1;

Those call the move/copy constructor, because a2 doesn't yet exist and needs to be constructed. Assigning doesn't make sense. This form is called copy-initialization.

a2 = std::move(a1);
a2 = a1;

Those call the move/copy assignment operator, because a2 already exists, so it doesn't make sense to construct it.

TartanLlama
  • 63,752
  • 13
  • 157
  • 193
0

Move constructor is called during:

  • initialization: T a = std::move(b); or T a(std::move(b));, where b is of type T;
  • function argument passing: f(std::move(a));, where a is of type T and f is void f(T t);

Move assignment operation is called during:

  • function return: return a; inside a function such as T f(), where a is of type T which has a move constructor.
  • assignment

The following example code illustrates this :

#include <iostream>
#include <utility>
#include <vector>
#include <string>
using namespace std;
class A {
    public :
    A() { cout << "constructor called" << endl;}
    ~A() { cout << "destructor called" << endl;}
    A(A&&) {cout << "move constructor called"<< endl; return;}
    A& operator=(A&&) {cout << "move assignment operator called"<< endl; return *this;}

};
A fun() {
    A a; // 5. constructor called
    return a; // 6. move assignment operator called
    // 7. destructor called on this local a
}
void foo(A){
    return;
}
int main()
{
    A a; // 1. constructor called 
    A b; // 2. constructor called
    A c{std::move(b)}; // 3. move constructor called
    c = std::move(a); // 4. move assignment operator called
    a = fun();
    foo(std::move(c)); // 8. move constructor called

}

Output :

constructor called
constructor called
move constructor called
move assignment operator called
constructor called
move assignment operator called
destructor called
move constructor called
destructor called
destructor called
destructor called
destructor called
novieq
  • 88
  • 1
  • 2
  • 14
  • "function argument passing" is a special case of "initialization" and I'm unsure what you mean by "function return". – el.pescado - нет войне Dec 04 '17 at 07:51
  • `return a;` is not mote-assignment – M.M Dec 04 '17 at 08:39
  • @M.M : please help me understand this as print out 6 (from inside fun() declaration) is move assignment operator called. – novieq Dec 04 '17 at 21:40
  • `a = fun();` move-assigns the return value to `a`. The line `return a;` move-constructs the return value from local variable `a`. Both of those operations might be elided – M.M Dec 04 '17 at 21:50