Reputation: 2822
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:
a2 = std::move(a1); // move-assignment from xvalue
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.
Upvotes: 22
Views: 16252
Reputation: 88
Move constructor is called during:
Move assignment operation is called during:
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
Upvotes: 0
Reputation: 254431
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.
Upvotes: 6
Reputation: 65600
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.
Upvotes: 4
Reputation: 56547
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.
Upvotes: 28