浅谈 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的左边
更准确的说
"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 要求不要依赖这个行为来编程
也就是可以一直认为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)
因此整体的分类如下