请查看以下示例代码:
#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
但我仍然不明白为什么。
任何人都可以帮助我吗?
答案 0 :(得分:4)
这只是Visual C ++通常的不合规性,允许将非const左值引用绑定到临时值。它违反了语言规则,但是在被捕获之前它已经太久了,所以现在的代码依赖于在正确修复时会破坏的错误。
错误地允许使用非const
复制构造函数的行为,加上Visual C ++版本中不完整的右值引用支持,显然会导致选择错误的重载。
如果你想使用C ++ 11 / C ++ 14的功能,你最好保持最新的Visual C ++版本。
答案 1 :(得分:3)
哇,当我用...编译时
Bar(Bar &that)
更改为Bar(const Bar &that)
,那么&#34;默认!移动&#34; <!/ LI>
Bar(Bar &that)
切换Bar(Bar &&that)
的顺序(以便首先定义移动ctor),那么您实际上会看到&#34;默认!移动&#34; <!/ LI>
醇>
答案 2 :(得分:-1)
您的问题可能已经回答here。
临时对象无法绑定到非const引用。复制构造函数必须引用const对象才能复制临时对象。
另一件事是临时物品不可修改,因为它们很快就会被销毁。持有对临时工具的引用会导致对不存在的对象的粗略修改。