为什么调用复制构造函数而不是移动构造函数
Why copy constructor is called instead of move constructor?
请查看以下示例代码:
#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!
我看不出为什么要调用复制构造函数而不是移动构造函数。如果我在struct Bar
的复制构造函数的声明中将关键字const
放在Bar &that
之前,我得到了正确的结果。我知道在很多情况下,对于复制构造函数,采用常量左值引用比只采用左值引用更好,但我只想知道发生这种情况的原因。
为什么在这个例子中Bar &
优先于Bar &&
,即使f()
的返回值应该被认为是prvalue?为什么关键字const
解决了这个问题?const
真的能解决问题吗?这与RVO(返回值优化)有关吗?或者,这只是一个编译器错误吗?
我已经在Visual C++2012年11月的CTP上测试了这个例子。
我在这里发现了一个类似的问题:
正在调用复制构造函数而不是移动构造函数
但我还是不明白为什么。
有人能帮我吗?
这只是Visual C++允许将非常常量左值引用绑定到临时值的常见违规行为。它违反了语言规则,但在被捕获之前已经过了很长时间,所以现在有一些代码依赖于错误,如果修复得当,就会崩溃。
这种错误地允许使用非const
复制构造函数的行为,再加上Visual C++版本中不完整的右值引用支持,显然会导致选择错误的重载。
如果你想使用C++11/C++14功能,你最好掌握最新的Visual C++版本。
哇,当我用。。。
- Visual Studio在调试中我看到"默认!复制!"
- Visual Studio发布版我看到了"默认!"
- 如果将
Bar(Bar &that)
更改为Bar(const Bar &that)
,则"默认!移动!" - 令人震惊的是,如果您将
Bar(Bar &that)
的顺序与Bar(Bar &&that)
切换(以便首先定义move ctor),那么您实际上会看到"Default!move!"
您的问题可能在这里得到了回答。
临时对象无法绑定到非常量引用。复制构造函数必须引用const对象才能复制临时对象。
另一件事是,临时物体不应被修改,因为它们很快就会被销毁。持有对临时性的引用会导致由于疏忽而对不存在的对象进行潜在的修改。
相关文章:
- 为什么不调用移动构造函数?(默认情况下只有构造器,没有别的)
- std::vector::p ush_back() 不会在 MSVC 上编译具有已删除移动构造函数的对象
- 仅包含可移动 std::map 的类的移动构造函数不起作用
- 为什么调用复制构造函数而不是移动构造函数?
- 基类中的默认析构函数禁用子类中的移动构造函数(如果有成员)
- 从具有按值捕获的 lambda 移动构造 std::函数时,移动构造函数调用两次
- 具有已删除移动和复制构造函数的类的就地构造
- 移动构造函数和右值引用
- 使用移动调用对等构造函数unique_ptr默认构造函数
- 为什么 std::memmove 中联合的默认非平凡移动构造函数C++?
- 具有专用化的模板类中的可靠条件复制和移动构造函数
- 构造函数采用std::string_view与std::string并移动
- C++:为什么不调用移动构造函数?
- 了解构造函数在移动、复制、赋值语义中的行为
- 没有移动的构造函数移动课程
- 引用绑定和复制构造函数/移动构造函数
- 构造函数移动
- C++ 向量实现 - 移动构造函数 - 移动与前进
- 我真的必须取消移动构造函数/移动结构中的所有成员还是只是指针
- 将类(没有默认构造函数)移动到另一个类的move构造函数中