c++ -- value category
2015-12-04 23:48
393 查看
c++ – value category
说到 value category ,可能大家都不知道是啥。但是说到左值,右值,可能很多人就听说了。C++将一个值作为左值、右值的分类称作 value category。说到 value category ,首先要强调一点,就是 value category 是值的属性,不是变量的属性。所谓值,就是表达式的结果,也就是说着也是表达式结果的一个属性。同时,表达式对其子表达式的结果的 value category 可能会有一定要求。因而说到左值右值,必须明确得到这个值的表达式,或者使用这个值的表达式,否则没有意义。
另外,这里所说的值可以是一个函数(函数本身,不是函数指针)。
value category
C++11 的 value category 其实并不只有左值、右值。C++11 的每一个值可以分为三类:lvalue, xvalue(eXpiring value), prvalue(pure rvalue)。然后,lvalue 与 xvalue 合称 glvalue (general lvalue);xvalue 与 prvalue 合称 rvalue。对各类的简要说明如下:
lvalue: 一个对象
xvalue: 也是一个对象,通常已经接近生存期的终点
glvalue: lvalue 与 xvalue
rvalue: xvalue, 临时对象,或前面两者的子对象,或没有对象的值
prvalue: 不是 xvalue 的 rvalue 。
仅依靠上面的说明来区分 value category 似乎有些困难,不过标准也没有期望能通过以上的说明区分不同 value category。标准采用的另一种方式定义 value category ,及明确的规定了每一种表达式的结果的 value category 。同时说明的每一种表达式所期望的操作数的 value category (对于操作数,没有说明的,就是 prvalue)。
下面简单介绍一下:
表达式的value category
在介绍表达式的 value category 之前,首先要说明一点,就是所有被重载过的操作符,均按照函数调用处理,他们的结果的 value category 参照函数调用结果的 value category 处理。多数表达式,如:
a++,
~a,
a+b,
&a,
this,lambda 表达式,
T(),
T{...},
T(v1,v2, ...)等,会产生一个 prvalue,除了以下情况:
literal 字面量 字符串常量为 lvalue 。其余常量为 prvalue。
(expression)与 expression 相同(即,括号不影响 value category)
id-expression:
identifier:函数、变量、数据成员为 lvalue ,其余为 prvalue
[注:函数的引用作为函数处理。对变量的左值引用与右值引用均为变量,因而他们都是 lvalue 。]
class::identifier: 静态成员函数与数据成员为 lvalue ,其它为 prvalue。
namespace::identifier:函数与变量为 lvalue ,其余为 prvalue
enumeration::enumerator: prvalue
subscribe
A: 其中一个操作数需要具有数组或指针类型。如果这个操作数是指针,结果为 lvalue;如果为数组,那么如果数组为lvalue,结果也是 lvalue,否则结果为 xvalue。
Function call:
func(...)与 类型转换:
dynamic_cast<T>(v),
static_cast<T>(v),
reinterpret_cast<T>(v),
const_cast<T>(v),
(T)v,
T(v)
返回值为 lvalue reference ,函数的 rvalue reference:lvalue
返回值为其它 rvalue reference :xvalue
其它:prvalue
类成员访问:
E1.E2
E2 为引用、静态成员变量:lvalue
E1为 lvalue ,E2 为非静态成员变量: lvalue
E1为 rvalue ,E2 为非静态成员变量: xvalue
E2 为静态成员函数:lvalue
E2 为非静态成员函数:prvalue
E2 为enumerator: prvalue
typeid(): lvalue
*p: lvalue
**
++,
--(前缀) : lvalue
E1.*E2
E2 是 pointer to data member, 若 E1 为 lvalue ,结果为 lvalue ,否则结果为 xvalue
E2 是 pointer to member function,结果为 prvalue
E1->*E2: 按
(*(E1)).*E2处理
E1?E2:E3如果 E2与E3类型与 value category 均相同,则结果的 value category 与 E2、E3相同。否则结果为 prvalue
a = b,
a op= b: lvalue
E1,E2: value category 与 E2 相同
左值引用与右值引用
引用需要绑定到一个表达式的值上。左值引用与右值引用的区分在于,他们所能绑定到的值的 value category 不同。一个简单的原则是,非 const 的左值引用需要绑定到一个左值,右值引用需要绑定到一个右值。
注意,左值引用或右值引用的变量(非函数引用)作为表达式出现的时候,结果都是一个左值。他们的区别体现在他们所能绑定到的对象上。
std::move
与 std::forward
[这一部分不考虑函数的问题。]从上面的介绍可以看到,一个变量,无论他是什么类型,即使它是一个右值引用,它独立形成一个表达式的时候,总是一个左值。那么如果想得到一个右值怎么办呢?这就是
std::move(v)的作用。它将生成它的参数的一个右值。其实做法很简单,
static_cast<remove_reference<T>&&>(v);。上面说了,类型转换生成一个右值引用时,结果为 xvalue ,是一个右值。
而
std::forward的作用则是,为右值引用生成一个右值,而对其它则保留为一个左值。
相关文章推荐
- Effective C++读书笔记-----条款20:宁以pass-by-reference-to-const替换pass-by-value
- vc++ 6.0 环境下结构体(数组)的操作类
- 基于c++11 的高精度计时器
- C语言实现动态数组
- C++返回值的“拷贝”问题
- C++ STL:stack和queue
- C++11的enum class & enum struct和enum
- 【C语言学习】封装和模块化思想
- VIBE背景建模算法之C语言实现
- 【codevs 3044 矩形面积合并】【poj 1151 Atlantis】【hdu 1542 Atlantis】题意&题解&代码(c++)
- C++调用CMD,等CMD运行完后继续运行C++
- C语言 scanf 函数返回值问题探究
- C语言命名
- C++学习笔记2015.10.5
- LibSVM C/C++
- LibSVM C/C++
- 复杂链表的复制(C++)
- Python实例浅谈之三Python与C/C++相互调用
- c++单独编译
- Python调用C/C++初步