函数中的r值参数

Bia*_*sta 18 c++ rvalue c++11

当在函数之间传递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).


Ker*_* SB 7

"rvalue reference"中的"rvalue"指的是引用可以绑定到的值的类型:

  • 左值引用可以绑定到左值
  • 右值引用可以绑定到右值
  • (+多一点)

这就是它的全部内容.重要的是,它不是使用引用时获得的值.一旦你有了一个引用变量(任何类型的引用!),id-expression命名该变量总是一个左值.Rvalues只在临时值中出现,或者作为函数调用表达式的值,或者作为强制转换表达式的值,或者作为衰减的结果或者this.

这里有一定的类比解引用指针:解引用指针始终是一个左值,无论是如何获得这个指针:*p,*(p + 1),*f()都是左值.你是怎么来的并不重要; 一旦你拥有它,它就是一个左值.

退一步,也许这一切中最有趣的方面是rvalue引用是一种将rvalue转换为左值的机制.在产生可变左值的C++ 11之前,没有这样的机制存在.虽然从左一开始,左值到右值的转换已成为该语言的一部分,但发现需要进行右值到右值的转换需要更长的时间.


How*_*ant 5

我现在的问题是为什么?

我添加另一个答案是因为我想强调“为什么”的答案。

尽管命名右值引用可以绑定到右值,但它们在使用时会被视为左值。例如:

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()

参考