【问题标题】:Exact difference between rvalue and lvalue右值和左值之间的确切区别
【发布时间】:2013-06-28 05:37:11
【问题描述】:

当我阅读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();不是错误。后一个是左值,而第一个是右值?

提前致谢

【问题讨论】:

  • 我相信你的最后一句话倒退了

标签: c++ c++11 rvalue


【解决方案1】:

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

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

}

为了真正理解上面的代码和所问的问题,必须稍微解释一下左值和右值的概念。在我们继续之前,您应该注意这里给出的左值和右值的定义并不准确,因为即使 C 标准本身在定义上也相当模糊。

右值和左值的区别

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

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

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

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

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

【讨论】:

  • 非常好,但是为什么要打扰这个例子呢?我看不出什么样的测验问题有助于理解这个问题。
【解决方案2】:

所以我们有两个函数:

int& foo();
int foobar();
  • foo 是一个将左值引用返回到 int 的函数
  • foobar 是一个返回 int 的函数

函数调用表达式:

foobar()
foo()

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

  • foobar() 是纯右值(对返回非引用的函数的函数调用是纯右值)
  • foo() 是左值(对返回左值引用的函数的函数调用是左值)

不能取右值的地址(右值是一种右值),所以&foobar()是不允许的。

你可以取一个左值的地址,所以&foo()是允许的。

【讨论】:

  • 为什么无法获取 foo 的地址?
  • @ss7don:你的意思是foo()这个表达式?你可以拿foo()的地址。再次阅读我答案的最后一行。
  • 我接受了这个答案,因为它看起来很合理。坦率地说,我仍然不明白 foo 和 foobar 之间的确切区别。两者都是函数。但是一个是右值,另一个是左值。
  • @ss7don:值类别是表达式的属性,而不是函数的属性。函数调用表达式的值类别是根据其返回类型计算的。函数 foo 的返回类型是int&。函数 foobar 的返回类型只有 int。引用 & 的存在或缺失决定了对该函数的函数调用的值类别。
  • 谢谢。现在,价值和功能之间的区别消除了我的疑问。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-03
  • 2021-05-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多