浅谈 Cpp Value Categories

Overview

背景

每一个cpp expression都有一个type 和 value category 属性 前者大家都比较了解,但是后者却常常被忽视

Value Categories in the c language

cpp是由c语言发展而来,因此这里先介绍c 语言中的value category

c语言只有简单的lvalue和rvalue两种

lvalue

lvalue的"l"表示"left",表示lvalue可以出现在assigment operator的左边

更准确的说

Tip

"lvalue is a value refer to an object" "an object is a region of storage"

所以通俗的说,lvalue就是可以取地址(存在storage region)的值 实际上编译器可能会对lvalue做优化,导致实际没有占用storage 但是cpp保证可以在编程时认为lvalue 一定是有占用storage的

rvalue

一切不是lvalue的值都是rvalue

  • 大部分字面量都是rvalue, 但是string(比如"hello world")不是
  • E1+E2是rvalue, 其中E1和E2不限制是何种value

但是实际上并不是所有的rvalue都不会占用storage 原因是字面量的空间是有限的,如果是一个非常大的int值,那么实际上可能是会占用地址的

然而,cpp 要求不要依赖这个行为来编程

Warning

也就是可以一直认为rvalue(non-class)是不会占用storage的 因此也不能取地址

为啥要区分lvalue 和rvalue?

原因之一是,编译器可以根据value category 做更多优化 比如对于如下代码

1
2int x = 3;

可以在汇编得到的代码中直接用立即数3而不是放在data storage中

lvalue-to-rvalue-conversion

如下这段代码中,n是lvalue,在赋值语句中用作了rvalue 这里c++实际上进行了一个 lvalue-to-rvalue-conversion

1int m,n;
2m = n;
3

rvalues of class type

当涉及到class type时,情况有了些不同 这里class type包含 class/struct/union 原因是访问成员变量时需要 base address + offset 的形式

因此rvalues of class type是实际会占用地址空间的

1
2struct S{
3  int x;
4  int y;
5};
6
7S foo(); // delcear a function that returns rvalue value of type S
8int j = foor().j;  // access y member of a rvalue
9

c++11时代

c++11 引入了rvalue reference. 为了避免非必要的copy

xvalue

  • 含义是"expiring value"
  • 函数的返回值如果是一个rvalue reference,那么结果就是一个xvalue 比如std::move(x)

因此整体的分类如下 分类

参考资料

Posts in this Series