[C++]左值和右值(LValue and RVaule) C++11版

C++11中对LValue和RValue的界定更加详细而合理(但是也更加麻烦了)

1章节:C++11的新分类介绍

2章节:不同值之间的转换

3章节:对一些常见的表达式,如何区分他们是什么值?

1. 表达式分类

所谓Value,是对表达式而言的。一个表达式可以分为以下几种Value,下边详细说明

1.1. lvalue(左值)

lvalue指代一个函数或者对象。例如:

  1. E是指针,则*E是lvalue
  2. 一个函数的返回值是左值引用,其返回值是lvalue。例如int& foo();

1.2. xvalue(expiring value,临终值)

xvalue指代一个对象,但是和lvalue不同,这个对象即将消亡。具体来说,xvalue是包含了右值引用的表达式。因为右值引用是C++11新引入的东西,所以xvalue也是一个新玩意。例如:

  1. 一个函数的返回值是右值引用,其返回值是xvalue。例如int&& foo();

1.3. glvalue(generalized lvalue,泛左值)

glvalue即lvalue和xvalue的统称。

1.4. rvalue(右值)

rvalue是xvalue和prvalue的统称。因为引入了右值引用,rvalue的定义在C++中被扩大化了。

1.5. prvalue(pure rvalue,纯右值)

prvalue指代一个临时对象、一个临时对象的子对象或者一个没有分配给任何对象的值。prvalue即老标准中的rvalue。例如:

  1. 一个函数的返回值是平常类型,其返回值是rvalue。例如int foo();
  2. 没有分配给任何对象的值。如5.3,true。

2. 表达式值类型的转换

glvalue → prvalue

其实表达式的转换,只有以上一途,也就是

  • lvalue → prvalue
  • xvalue → prvalue

2.1. lvalue → prvalue

这个很常见:glvalue(lvalue和xvalue)可以隐式转换为prvalue来满足需求。例如:

int& foo(int val) // 函数接受prvalue

{

    int a = val + 1;

    return a;

}



int main()

{

    int i = 5;

    cout << foo(4) << endl; // 传递进去一个prvalue

    cout << foo(i) << endl; // 传递进去一个lvalue

    cout << foo(foo(i)) << endl; // foo(i)返回lvalue,传递至外层函数

    system("pause");

}

当然,这个函数写的不大好,不应该将临时对象传递出函数的~

如果将foo改写为下面这样,上边的代码就不能工作了,因为prvalue→lvalue是不成滴~

int& foo(int val)

{

    return val + 1;

}

2.2. cv-qualifier的解除

在其他转换中,const转换是不能去除的,但是glvalue到prvalue的转换是可以去除的。这个说辞比较晦涩,其实十分常见,比如:

const int a = 5;

int b = a; // b = ? 这个需要右值,所以把a先转为右值,同时丢弃了const限定词

3. 表达式值类型的判定

C++的每一个表达式都有其值类型,换句话说,任何表达式,都属于以下三者之一:lvalue,xvalue,prvalue。

如果是简单的表达式自然很好理解,如上一节所举的变量、常量以及返回值。但是大部分情况都要复杂得多。

2.1. C++内建操作的判定

这个就要具体操作具体分析了。C++的内建操作对操作数的类型做出了详细的界定,对整个操作代表的类型也做出了详细的界定。例如:

分配运算 op1 = op2。op1是lvalue,op2是rvalue。整个操作是lvalue

2.2. 用户定义的操作

用户定义操作,无非就是自建函数。(恩,没错,C++的操作符重载也是函数重载~~)操作数等价于函数参数,操作yield值相当于函数返回值。其类型都由用户界定。例如:

  1. int foo(int); 参数是prvalue,返回值是prvalue。
  2. int& foo(int); 参数是prvalue,返回值是lvalue。u

你可能感兴趣的:(value)