移动赋值运算符和移动构造函数之间的区别?

时间:2015-04-30 15:02:21

标签: c++ c++11 constructor move-semantics

有一段时间,这让我感到困惑。到目前为止,我还没有找到满意的答案。问题很简单。何时调用move assignment operator,何时调用move constructor operator

cppreference.com上的代码示例产生以下有趣结果:

The move assignment operator:

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

The move constructor:

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

它是如何实现的?如果是这样的话,如果两者都实施了吗?如果它完全相同,为什么有可能创建一个移动赋值运算符重载。

4 个答案:

答案 0 :(得分:13)

只有在构造对象时才会执行移动构造函数。移动赋值运算符在先前构造的对象上执行。这与复制案例完全相同。

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

如果您没有明确声明它们,编译器会为您生成它们(除了一些例外,其列表太长,无法在此处发布)。

有关隐式生成移动成员函数的完整答案,请参阅this

答案 1 :(得分:4)

  

何时调用移动赋值运算符

rvalue 分配给对象时,就像在第一个示例中一样。

  

何时调用移动构造函数?

使用 rvalue 初始化对象时,就像在第二个示例中一样。虽然它不是运营商。

  

它实现了吗?

不,这决定了它是否可以使用,而不是可以使用它。例如,如果没有移动构造函数,那么构造将使用复制构造函数(如果存在),否则失败(带错误)。

  

如果是这样的话,如果两者都实施了吗?

赋值赋值运算符,初始化构造函数。

  

为什么有可能创建一个移动赋值运算符重载,无论如何它都是相同的。

不完全相同。它是在已经存在的对象上调用的;调用构造函数以初始化以前不存在的对象。他们经常要做不同的事情。例如,赋值可能必须删除在初始化期间不存在的内容。

答案 2 :(得分:2)

这与正常的复制分配和复制构造相同。

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

那些调用move / copy构造函数,因为a2尚不存在且需要构造。分配没有意义。此表单称为复制初始化。

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

那些调用移动/复制赋值运算符,因为a2已经存在,所以构造它没有意义。

答案 3 :(得分:0)

在以下期间调用移动构造函数:

  • 初始化:T a = std :: move(b);或者T a(std :: move(b));,其中b是T的类型;
  • 函数参数传递:f(std :: move(a));,其中a是T类型,f是void f(T t);

在以下期间调用移动分配操作:

  • 功能返回:返回a;在诸如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