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

时间:2015-04-05 15:44:18

标签: c++11 copy-constructor move-semantics rvalue-reference rvo

请查看以下示例代码:

   #include <iostream>

    struct Foo {
        Foo() { std::cout << "Default!\n"; }
        Foo(const Foo& foo) { std::cout << "Copy!\n"; }
        Foo(Foo&& foo) { std::cout << "Move!\n"; }
    };

    struct Bar {
        Foo foo;
        Bar() {}
        Bar(Bar &that) : foo(that.foo) {}
        Bar(Bar &&that) : foo(std::move(that.foo)) {}
    };

    Bar f() {
        Bar bar;
        return bar;
    }

    int main() {
        Bar bar(f());
    }

我希望此代码的输出应为:

Default!
Move!

但我得到的是:

Default!
Copy!

我无法看到为什么调用复制构造函数而不是移动构造函数的原因。如果我在const的复制构造函数的声明中将关键字Bar &that放在struct Bar前面,我就得到了正确的结果。我知道在很多情况下采用const左值引用而不仅仅是复制构造函数的左值引用更好,但我只是想知道发生这种情况的原因。

为什么在此示例中Bar &优先于Bar &&,即使f()的返回值应被视为prvalue?为什么关键字const可以解决问题? const真的解决了这个问题吗?它与RVO(返回值优化)有关吗?或者,这只是一个编译器错误吗?

我在Visual C ++ 2012年11月的CTP上测试了这个例子。

我在这里发现了类似的问题:

Copy constructor is being called instead of the move constructor

但我仍然不明白为什么。

任何人都可以帮助我吗?

3 个答案:

答案 0 :(得分:4)

这只是Visual C ++通常的不合规性,允许将非const左值引用绑定到临时值。它违反了语言规则,但是在被捕获之前它已经太久了,所以现在的代码依赖于在正确修复时会破坏的错误。

错误地允许使用非const复制构造函数的行为,加上Visual C ++版本中不完整的右值引用支持,显然会导致选择错误的重载。

如果你想使用C ++ 11 / C ++ 14的功能,你最好保持最新的Visual C ++版本。

答案 1 :(得分:3)

哇,当我用...编译时

  1. Debug中的Visual Studio我看到&#34;默认! !拷贝&#34;
  2. 发布中的Visual Studio我看到&#34;默认!&#34;。
  3. 如果您将Bar(Bar &that)更改为Bar(const Bar &that),那么&#34;默认!移动&#34; <!/ LI>
  4. 令人震惊的是,如果您使用Bar(Bar &that)切换Bar(Bar &&that)的顺序(以便首先定义移动ctor),那么您实际上会看到&#34;默认!移动&#34; <!/ LI>

答案 2 :(得分:-1)

您的问题可能已经回答here

  

临时对象无法绑定到非const引用。复制构造函数必须引用const对象才能复制临时对象。

另一件事是临时物品不可修改,因为它们很快就会被销毁。持有对临时工具的引用会导致对不存在的对象的粗略修改。