rvalue和lvalue之间的确切差异

时间:2013-06-28 05:37:12

标签: c++ c++11 rvalue

在我阅读http://thbecker.net/articles/rvalue_references/section_01.html时,我听到了最令人沮丧的事情。

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

// rvalues:
//
int foobar();
int j = 0;
j = foobar(); // ok, foobar() is an rvalue
int* p2 = &foobar(); // error, cannot take the address of an rvalue
j = 42; // ok, 42 is an rvalue

为什么int * p2 =& foobar();是错误语句,而int * p1 =& foo();不是错误。如果一个是右值,那么第一个是左值是多少呢?

提前致谢

2 个答案:

答案 0 :(得分:9)

假设我们在C中有如下所示的示例代码。它会编译吗?左值和右值的概念如何在这个问题中起作用?

#define X 8
int main(void)
{
    ++X; // will this line compile?
        return 0;

}

为了真正理解上面的代码和问题,必须对lvalues和rvalues的概念进行一些解释。在我们继续之前,你应该注意到这里提出的左值和左值的定义并不准确,因为即使C标准本身在定义上也是相当模糊的。

rvalues和lvalues之间的区别

对象是可以检查但不一定要修改的内存区域。左值是一个引用这种对象的表达式。术语“左值”最初指的是出现在表达式左侧(因此“l”)手侧的对象。该定义不再适用,因为任何const限定类型也被认为是左值,但它永远不会出现在赋值语句的左侧,因为它无法修改。因此,创建术语“可修改左值”以引用可以修改的左值,并且const限定类型不属于此类别。

rvalue是具有值的任何表达式,但不能为其分配值。也可以说rvalue是任何不是左值的表达式。右值的一个例子是文字常量 - 类似'8'或'3.14'。所以,显然上面代码中的值'8'是一个右值。

使用我们对左值和右值的理解来回答问题

现在让我们尝试解决问题。严格地说,前缀(或后缀)增量运算符的操作数必须是可修改的左值。那么,上面代码中前缀增量运算符的操作数是什么?

由于X是一个宏,因此在运行预处理器之后,上面的语句将扩展为“++ 8”。这意味着“8”是前缀增量运算符的操作数。并且,因为8是一个rvalue,所以它不能用作“++”的参数。反过来,这意味着上面的代码将无法编译。

答案 1 :(得分:5)

所以我们有两个功能:

int& foo();
int foobar();
  • foo是一个返回lvalue-reference to int
  • 的函数
  • foobar是一个返回int的函数

函数调用表达式:

foobar()
foo()

都具有int类型(引用从表达式中删除,因此foo()具有类型int而不是lvalue-reference to int)。这两个表达式具有不同的值类别:

  • foobar()是一个prvalue(对返回非引用的函数的函数调用是一个prvalue)
  • foo()是左值(对函数的函数调用返回左值引用是左值)

你不能取rvalue的地址(prvalue是一种rvalue),所以不允许使用&foobar()

您可以使用左值的地址,以便&foo()被允许。