C++:函数lvalue还是rvalue

9

我刚开始阅读这篇文章学习C++11中的右值引用,但是在第一页就卡住了。下面是我从页面中摘取的代码。

  int& foo();
  foo() = 42; // ok, foo() is an lvalue
  int* p1 = &foo(); // ok, foo() is an lvalue

  int foobar();
  j = foobar(); // ok, foobar() is an rvalue
  int* p2 = &foobar(); // error, cannot take the address of an rvalue
  1. 为什么foo()是左值?是因为foo()返回的是int&,基本上就是左值。
  2. 为什么foobar()是右值?是因为foobar()返回的是int
  3. 一般来说,您为什么要关心函数是否是右值?我认为如果我读完那篇文章,就能得到答案。
1个回答

17

L-Values(左值)是位置,R-Values(右值)是可存储的值(即可被赋值的值,例如命名空间就不可赋值;感谢@Maggyero提供编辑建议)。

所以:

  1. 由于foo()返回一个引用(int&),这使它本身成为了一个L-Value。
  2. 正确。 foobar() 是一个 R-Value,因为 foobar() 返回 int
  3. 我们并不是特别关心函数是否是 R-Value。我们感兴趣的是 R-Value 引用。

您指出的文章很有趣,我之前没有考虑过转发或在工厂中使用。我对 R-Value 引用感到兴奋的原因是移动语义,例如:

BigClass my_function (const int& val, const OtherClass & valb);

BigClass x;
x = my_function(5, other_class_instance);

在这个例子中,x会被销毁,然后my_function的返回值会通过复制构造函数被复制到x中。为了避免这种情况,在历史上你可以这样写:
void my_function (BigClass *ret, const int& val, const OtherClass & valb);

BigClass x;
my_function(&x, 5, other_class_instance);

这意味着现在my_function有副作用,而且阅读起来不是很清晰。现在,使用C++11,我们可以这样编写代码:
BigClass & my_function (const int& val, const OtherClass & valb);

BigClass x;
x = my_function(5, other_class_instance);

让它的运行效率和第二个例子一样高。

2
“R-Values are actual values”更准确地说,R-Values是可存储的值。一些值在C++中无法被分配,因此不是R-Values,例如类型、命名空间等。 - Géry Ogam
@Maggyero 命名空间和类型根本不是值。并非所有带名称的东西都是值。 - Caleth
@Caleth 值是表达式的含义。由于命名空间和类型并非毫无意义,它们确实具有值。您可以查看Dana Scott和Christopher Strachey关于指称语义的工作。不过我认为目前尚未发布C++的指称语义。目前它仅在ISO C++标准中以自然语言进行说明。 - Géry Ogam
@Maggyero C++标准中讨论了basic.lval中的值,命名空间和类型不是表达式(尽管命名空间名称和类型名称可以与表达式一起出现)。“glvalue的结果是由表达式表示的实体。prvalue的结果是表达式存储到其上下文中的值;具有cv void类型的prvalue没有结果。有时称其结果为值V的prvalue被认为具有或命名值V。” - Caleth
在指称语义中,@Caleth A value(或denotation)是ISO C++标准术语中所谓的entity。 在指称语义中,stored value(或stored denotation)是ISO C++标准中所谓的value。 命名空间和类型是指称语义术语中的值,也是ISO C++标准中的实体。 - Géry Ogam
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接