当在函数之间传递r值时,我想知道c ++行为.
看看这个简单的代码:
#include <string>
void foo(std::string&& str) {
// Accept a rvalue of str
}
void bar(std::string&& str) {
// foo(str); // Does not compile. Compiler says cannot bind lvalue into rvalue.
foo(std::move(str)); // It feels like a re-casting into a r-value?
}
int main(int argc, char *argv[]) {
bar(std::string("c++_rvalue"));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我知道当我在bar函数内部时我需要使用move函数来调用foo函数.我现在的问题是为什么?
当我在bar函数内部时,变量str应该已经是一个r值,但编译器就像是一个l值.
有人可以引用一些关于这种行为的标准吗?谢谢!
Rak*_*111 11
str是一个右值引用,即它只是对rvalues的引用.但它仍然是一个参考,这是一个左值.您可以将其str用作变量,这也意味着它是左值,而不是临时右值.
的左值,根据§3.10.1.1:
左值(历史上所谓的左值,因为左值可能出现在赋值表达式的左侧)指定一个函数或一个对象.[ 实施例:如果ê是指针类型的表达式,然后*E是一个左值表达式参考对象或函数,其È点.另一个例子,调用返回类型为左值引用的函数的结果是左值.- 结束例子 ]
和右值,根据§3.10.1.4:
的右值(所谓的,历史上,因为右值可以出现在赋值表达式的右手侧)是x值,一个临时对象(12.2)或者子对象,或它们的不与一个对象相关联的值.
基于此,str不是暂时对象,而且它是与对象(与所谓的该对象相关联str),并且因此它不是一个rvalue.
左值的示例使用指针,但它对于引用是相同的,对于右值引用(它们只是一种特殊类型的引用)自然而然.
所以,在你的例子中,str 是一个左值,所以你必须std::move调用它foo(它只接受rvalues,而不是lvalues).
"rvalue reference"中的"rvalue"指的是引用可以绑定到的值的类型:
这就是它的全部内容.重要的是,它不是指使用引用时获得的值.一旦你有了一个引用变量(任何类型的引用!),id-expression命名该变量总是一个左值.Rvalues只在临时值中出现,或者作为函数调用表达式的值,或者作为强制转换表达式的值,或者作为衰减的结果或者this.
这里有一定的类比解引用指针:解引用指针始终是一个左值,无论是如何获得这个指针:*p,*(p + 1),*f()都是左值.你是怎么来的并不重要; 一旦你拥有它,它就是一个左值.
退一步,也许这一切中最有趣的方面是rvalue引用是一种将rvalue转换为左值的机制.在产生可变左值的C++ 11之前,没有这样的机制存在.虽然从左一开始,左值到右值的转换已成为该语言的一部分,但发现需要进行右值到右值的转换需要更长的时间.
我现在的问题是为什么?
我添加另一个答案是因为我想强调“为什么”的答案。
尽管命名右值引用可以绑定到右值,但它们在使用时会被视为左值。例如:
struct A {};
void h(const A&);
void h(A&&);
void g(const A&);
void g(A&&);
void f(A&& a)
{
g(a); // calls g(const A&)
h(a); // calls h(const A&)
}
Run Code Online (Sandbox Code Playgroud)
虽然右值可以绑定到 的a参数f(),但一旦绑定,a现在就被视为左值。特别是,调用重载函数g()并h()解析为const A&(左值)重载。将a其视为右值f会导致容易出错的代码:首先将调用 的“移动版本” g(),这可能会窃取a,然后将窃取的内容a发送到 的移动重载h()。
参考。
| 归档时间: |
|
| 查看次数: |
3552 次 |
| 最近记录: |