为什么我必须在右值引用上调用move ?
Why do I have to call move on an rvalue reference?
在下面的代码中,为什么第一个调用不将mkme = mvme_rv
分派给T& operator=(const T&&)
呢?
#include <iostream>
#include <string>
#include <vector>
using namespace std;
using T = vector<int>;
int main()
{
T mvme(10, 1), mkme;
T&& mvme_rv = move(mvme); // rvalue ref?
mkme = mvme_rv; // calls T& operator=(const T&)?
cout << mvme.empty(); // 0
mkme = move(mvme_rv); // calls T& operator=(const T&&)?
cout << mvme.empty(); // 1
}
正如skypjack正确注释的那样,通过名称访问对象总是导致左值引用。
这是一个安全功能,如果你仔细考虑一下,你会意识到你很喜欢它。
如您所知,std::move
只是将左值引用强制转换为右值引用。如果我们立即使用返回的r值引用(即未命名),那么它仍然是一个r值引用。
这意味着r值只能在代码中提到move(x)
的地方使用。从代码读者的角度来看,现在很容易看出x的状态在哪里变为undefined。
:
1: auto x = make_x();
2: auto&& r = std::move(x);
3: // lots of other stuff
35: // ...
54: // ...
55: take_my_x(r);
不起作用。如果是这样,维护代码的人将很难看到(并记住)x(在第1行定义)通过第2行引用在第55行进入未定义状态。
这个更显式:
1: auto x = make_x();
2: //
3: // lots of other stuff
35: // ...
54: // ...
55: take_my_x(std::move(x));
这行代码:
mkme = mvme_rv;
是一个副本,因此将使用副本赋值(T& operator=(const T&)
)。关键是两个对象都可以在之后使用,如果实现正确的话,应该提供两个相同的对象。
相比之下,这行代码:
mkme = move(mvme_rv);
是一个移动赋值(T& operator=(const T&&)
)。按照惯例,这将废弃mvme_rv
对象(或者至少清除它),并使mkme
基本上与mvme_rv
相同。
有效地T&&
意味着一个临时对象(又名xvalue) -不会持续的东西。std::move
方法基本上将对象转换为临时对象(感谢@richard-Hodges的措辞)。这可以在move赋值方法中使用。
所以最后回答你的问题为什么mkme = mvme_rv
不调度到T& operator=(const T&&)
:它是因为mvme_rv
不是一个临时对象(又名xvalue)。
关于xvalues的更多信息:http://en.cppreference.com/w/cpp/language/value_category
- 如何在 c# 代码中通过引用调用时从 c++ dll 更新数组值?
- 推理类型如何工作"auto"和按引用调用?
- C++ 通过引用调用函数
- 按引用调用与按指针参数调用的差异 前递增和后递增
- C++当您取消引用指向类对象的指针,然后将其作为引用返回时,是否可以对此引用调用方法
- 通过引用调用模板专用化
- 为什么通过带有文字编号的引用调用会出现"无匹配函数"错误?
- 按引用调用还是按值调用?
- 从 JS (V8) 中C++对象的引用调用函数
- 为什么要抛出引用调用复制构造函数的异常?
- 向量 - 通过引用 c++ 调用
- 为什么可以从常量引用调用析构函数
- 使用全局引用调用函数时访问冲突
- 引用调用在 c++ 中如何工作?
- 它不是编译.我正在调用一个通过引用调用的函数,但有一个错误,无法将双*转换为双倍
- C++函数调用 lambda obj,按值调用比按引用调用快
- 如何在 C++14 中编写用于调用 Fortran 函数的通用包装器(按引用调用 --按值调用>)
- 通过引用调用类对象的 2D 数组
- 构造函数参数中的引用调用引用的默认构造函数
- 如何在 main 中使用包含对节点的引用调用函数