移动赋值运算符和移动构造函数之间的区别?
Difference between the move assignment operator and move constructor?
一段时间以来,这一直让我感到困惑。到目前为止,我还没有找到满意的答案。问题很简单。 move assignment operator
什么时候被调用,move constructor operator
什么时候被调用?
cppreference.com 上的代码示例产生了以下有趣的结果:
a2 = std::move(a1); // move-assignment from xvalue
A a2 = std::move(a1); // move-construct from xvalue
那么它与实现的有什么关系呢?如果是的话,如果两者都实现了,执行哪个?为什么有可能创建一个移动赋值运算符重载,如果它无论如何都是相同的。
移动构造函数仅在构造对象时执行。对先前构造的对象执行移动赋值运算符。与复制案例中的场景完全相同。
Foo foo = std::move(bar); // construction, invokes move constructor
foo = std::move(other); // assignment, invokes move assignment operator
如果您没有显式声明它们,编译器会为您生成它们(除了一些例外,其列表太长而无法在此处发布)。
有关何时隐式生成移动成员函数的完整答案,请参阅 this。
这与正常的复制赋值和复制构造相同。
A a2 = std::move(a1);
A a2 = a1;
那些调用 move/copy 构造函数,因为 a2
还不存在,需要构造。分配没有意义。这种形式称为复制初始化。
a2 = std::move(a1);
a2 = a1;
那些调用move/copy赋值运算符的,因为a2
已经存在,所以构造它没有意义。
When does a move assignment operator get called
当您将 rvalue 分配给一个对象时,就像您在第一个示例中所做的那样。
and when does a move constructor operator get called?
当您使用 rvalue 初始化对象时,就像您在第二个示例中所做的那样。虽然不是运营商。
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.
不完全相同。它是在一个已经存在的对象上调用的;调用构造函数来初始化一个以前不存在的对象。他们经常不得不做不同的事情。例如,赋值可能必须删除一些在初始化期间不存在的东西。
在以下期间调用移动构造函数:
- 初始化:T a = std::move(b);或 T a(std::move(b));,其中 b 的类型为 T;
- 函数参数传递:f(std::move(a));,其中a是T类型,f是void f(T t);
在以下期间调用移动赋值操作:
- 函数return:return一个;在诸如 T f() 之类的函数中,其中 a 是具有移动构造函数的 T 类型。
- 作业
以下示例代码说明了这一点:
#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
}
输出:
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
一段时间以来,这一直让我感到困惑。到目前为止,我还没有找到满意的答案。问题很简单。 move assignment operator
什么时候被调用,move constructor operator
什么时候被调用?
cppreference.com 上的代码示例产生了以下有趣的结果:
a2 = std::move(a1); // move-assignment from xvalue
A a2 = std::move(a1); // move-construct from xvalue
那么它与实现的有什么关系呢?如果是的话,如果两者都实现了,执行哪个?为什么有可能创建一个移动赋值运算符重载,如果它无论如何都是相同的。
移动构造函数仅在构造对象时执行。对先前构造的对象执行移动赋值运算符。与复制案例中的场景完全相同。
Foo foo = std::move(bar); // construction, invokes move constructor
foo = std::move(other); // assignment, invokes move assignment operator
如果您没有显式声明它们,编译器会为您生成它们(除了一些例外,其列表太长而无法在此处发布)。
有关何时隐式生成移动成员函数的完整答案,请参阅 this。
这与正常的复制赋值和复制构造相同。
A a2 = std::move(a1);
A a2 = a1;
那些调用 move/copy 构造函数,因为 a2
还不存在,需要构造。分配没有意义。这种形式称为复制初始化。
a2 = std::move(a1);
a2 = a1;
那些调用move/copy赋值运算符的,因为a2
已经存在,所以构造它没有意义。
When does a move assignment operator get called
当您将 rvalue 分配给一个对象时,就像您在第一个示例中所做的那样。
and when does a move constructor operator get called?
当您使用 rvalue 初始化对象时,就像您在第二个示例中所做的那样。虽然不是运营商。
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.
不完全相同。它是在一个已经存在的对象上调用的;调用构造函数来初始化一个以前不存在的对象。他们经常不得不做不同的事情。例如,赋值可能必须删除一些在初始化期间不存在的东西。
在以下期间调用移动构造函数:
- 初始化:T a = std::move(b);或 T a(std::move(b));,其中 b 的类型为 T;
- 函数参数传递:f(std::move(a));,其中a是T类型,f是void f(T t);
在以下期间调用移动赋值操作:
- 函数return:return一个;在诸如 T f() 之类的函数中,其中 a 是具有移动构造函数的 T 类型。
- 作业
以下示例代码说明了这一点:
#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
}
输出:
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