为什么编译器使用移动构造函数而不是复制构造函数

时间:2017-08-11 01:30:37

标签: c++ c++11

以下代码是否正常

#include <iostream>

struct Foo
{
    Foo() { std::cout << "Foo::Foo" << std::endl; }
    ~Foo() { std::cout << "Foo::~Foo" << std::endl; }

    Foo(const Foo&) { std::cout << "Foo::Foo(const Foo&)" << std::endl; }
    Foo& operator=(const Foo&) { std::cout << "Foo::operator=(const Foo&)" << std::endl; return *this; }

    Foo(Foo&&) { std::cout << "Foo::Foo(Foo&&)" << std::endl; }
    Foo& operator=(Foo&&) { std::cout << "Foo::operator=(Foo&&)" << std::endl; return *this; }
};

Foo foo()
{
    Foo second;
    return second;
}

int main()
{
    foo();
}

产生这样的输出:

Foo::Foo
Foo::Foo(Foo&&)
Foo::~Foo
Foo::~Foo

为什么调用移动构造函数而不是复制构造函数?

1 个答案:

答案 0 :(得分:3)

答案很简单,因为标准是这样说的。第12.8节,第32段:

  

当满足复制/移动操作的省略标准时,但不符合例外声明,并且   要复制的对象由左值指定,或者当返回语句中的表达式为(可能是   parenthesized)id-expression命名一个具有在body中声明的自动存储持续时间的对象   最内层封闭函数或lambda表达式的参数声明子句,重载决策   首先执行选择复制的构造函数,就好像该对象是由右值指定的。

基本上就是这一切。逻辑上,如果变量具有自动存储持续时间,并且您return它,那么在返回之后,当本地范围清除时,该变量将不再存在。这就是为什么,即使它是左值,它也非常类似于右值。因为它在技术上仍然是一个左值,所以必须在标准中明确地做出这个例外,我们就是这样。请注意,整个情况特定于return来自函数,并且不包括范围一般结束。