左值与右值

来源:互联网 发布:网络文字录入员 编辑:程序博客网 时间:2024/05/21 12:46

左值与右值

在学习C++11右值引用前,我们必须首先了解什么是左值(lvalue)和右值(rvalue)。

对于上述两个概念,想要给出一个严谨的定义是非常困难的。

但是,下面的解释对于我们学习右值引用来说已经足够了(以及后续的移动语义和完美转发)。

在早期的C语言中,关于左值和右值的定义是这样的(主要是为了帮助记忆):一个左值是可以出现在赋值运算符左边或右边的一个表达式。一个右值则是只能出现在赋值操作符右边的一个表达式。

    int a = 42; // 表达式a是左值,字面值常量42是右值    int b = 43; // 表达式b是左值,字面值常量43是右值    a = b; // 表达式a和表达式b都是左值    b = a; // 表达式a和表达式b都是左值    a = a * b; // 表达式a是左值, 表达式a*b是右值    int c = a * b; // ok,表达式c是左值,表达式a*b是右值    a * b = 42; // error,表达式a*b是右值,右值不能出现在赋值操作符的左边                //lvalue required as left operand of assignment

然而在C++语言中,随着用户自定义类引入了关于可变性(modifiability)和可转让性(assignability)的微妙变化,左值和右值二者的区别就没有那么简单了。

比如,一个左值表达式的求值结果是一个对象或者一个函数,然而以常量对象为代表的某些左值实际上不能作为赋值语句的左侧运算对象。此外,虽然某些表达式的求值结果是对象,但它们是右值而非左值。

接下来是另一份对左值和右值的定义,虽说它可能依然经不起推敲,但是可以让你用来处理右值引用:

在C++语言中,所有的表达式要么是左值,要么是右值。当一个对象被用作右值的时候,用的是对象的值(内容);当对象被用作左值的时候,用的是对象的身份(在内存中的位置)。

常见的左值/右值总结如下:

  • 赋值运算符(=)的左侧运算对象必须是一个非常量的左值,其结果也仍然是一个左值。
  • 递增和递减运算符(++和–)必须作用于左值运算对象,前置版本将对象本身作为左值返回,后置版本则将对象原始值的副本作为右值返回。
  • 箭头运算符(->)作用于一个指针类型的运算对象,结果是一个左值。
  • 点运算符(.)分成两种情况:
    • 如果成员所属的对象是左值,那么结果是左值。
    • 如果成员所属的对象是右值,那么结果是右值。
  • 条件运算符(? :)的两个表达式都是左值或者能转换成同一种左值类型时,运算的结果是左值;否则运算的结果是右值。
  • 取地址运算符(&)作用于一个左值运算对象,返回一个指向该运算对象的指针,这个指针是一个右值。
  • 内置解引用运算符*、迭代器解引用运算符*、内置下标运算符[]、容器下标运算符[]的求值结果都是左值。
  • 算术运算符的运算对象和求值结果都是右值。
  • 逻辑运算符(!,&&,||)的运算对象和求值结果都是右值。
  • 关系运算符(<,<=,>,>=,==,!=)的运算对象和求值结果都是右值。
  • 函数的返回类型决定函数调用是否是左值。
    • 调用一个返回引用类型的函数得到左值。
    • 调用一个返回其他类型的函数得到右值。

左值持久,右值短暂

左值有持久的状态,而右值要么是字面值常量,要么是在表达式求值过程中创建的临时对象。

变量是左值

变量可以看作只有一个运算对象而没有运算符的表达式,虽然我们很少这样看待变量。

类似其他任何表达式,变量表达式也有左值/右值属性。

变量表达式都是左值。(变量是持久的,直到离开作用域时才被销毁)

原创粉丝点击