示例地址:值类别示例
1概述
每一个表达式都由类型和值类别来辨别,每个表达式都有一个非引用的类型,和一个值类别
值类别从C++11出现右值引用以后发生了翻天覆地的变化,C++98是继承C的分类法,即左值,右值
C++11之后则细分为,左值,纯右值,亡值三个细类,其中引申出的泛左值包含了左值和亡值,右值则是包含了纯右值和亡值
对这三个引申值类别的概述是:
泛左值:
表明,该表达式的值确定一个对象,位域,或函数
右值:
计算某个运算符的操作数的值,只需要一个操作数值即可,此时不存在结果对象
初始化对象,或位域,此时存在一个用于初始化的结果对象,所有类和数组的纯右值都有结果对象,在某些语境下则会出现临时实质化,创建一个用于计算结果的对象(结果对象)
亡值:
表示资源能够被重新使用的对象或位域的泛左值
2左值
左值可以是:
变量,函数,数据成员的名字(名字请见标识符段概述)即一个实体的名字,或是引用的名字(包含左值右值的)
返回左值引用的函数调用或重载运算符的表达式
所有赋值及其复合赋值运算符表达式
前置自增自减表达式
间接寻址表达式(内建的)
数组内建的下标访问表达式,除非数组是一个右值(特殊情况,通过数组类名直接用花括构建,此时数组即为一个结果对象)
当前对象为左值时,访问的对象不为非静成员函数或枚举项,当对象为右值时访问的对象是非引用的非静态数据成员时,内建的对象成员表达式(.)
当访问的对象不为非静态成员函数或枚举项时,对象指针通过内建的指针成员表达式
当对象为左值切指针指向成员是数据成员时的对象成员指针表达式
当对象指针的类指针指向的成员是数据成员时的指针成员指针表达式
字符串字面量
转换为左值引用的类型转换表达式
返回函数右值引用的函数调用或重载运算符表达式
转换为函数右值引用的类型转换表达式
3纯右值:
除了字符串字面量的字面量
返回非引用的函数调用或重载运算符表达式
后置自增表达式
除了赋值及其复合赋值之外的算术表达式
内建的逻辑和比较表达式
内建的取址表达式
内建的对象成员为非静态函数或枚举项的对象成员表达式
内建的对象成员位非静态函数或枚举项的指针成员表达式
当对象指向成员是函数成员时的对象成员指针表达式
当对象指针的类指针指向的成员是函数成员时的指针成员指针表达式
转换为非引用类型的类型转换表达式
this
枚举项
lambda表达式
4亡值
返回右值引用的函数调用或重载运算符表达式
右值数组的下标访问
对象成员表达式,其中对象是右值并且成员是非引用类型的非静态数据成员
对象的成员指针表达式,其中对象是右值并且成员指针指向数据成员
转换为右值引用的类型转换表达式
5性质
泛左值:
左值
左值可以被取地质,可修改的左值可以使用内建的赋值和内建复和赋值运算数的左操作数,可以用作初始化左值引用
泛左值可以通过左值到右值,数组到指针,或函数到指针形成纯右值,可以是多态的,可以是不完整类型,只要表达式允许
亡值
亡值可以绑定到右值引用,并且可以是多态的,非类型的亡值可以有cv限定
右值:
纯右值:
纯右值不能多态,非类非数组纯的右值不能有cv限定,函数调用,类型转换表达式,可能会生成cv限定的纯右值,但是会被立刻剥离,纯右值不能不具有完整类型
右值不能被取址,不能左为内建的赋值,复合赋值表达式的左运算数,可以初始化const的左值引用或右值引用,此时右值的生存周期将被延长到引用的声明周期结束,存在参数为const的左值引用和右值引用的重载函数时,右值首先绑定右值引用,因为更加特化。
6其他特殊类别
对于非静态成员函数而言,所有绑定准确对象后进行访问的行为的表达式都是纯右值,即obj.func,或obj.*pfunc此时这个表达式智能作为函数调用运算符的左操作数
返回void,转换为void类型,throw表达式都是纯右值表达式,只可以出现在弃值语境内(参考表达式节)
代表某个位域的表达式时左值表达式,它可以作为赋值系列表达式的左值,但是不能被取址,但是不能绑定非const的左值引用,const的左值引用可以被位域初始化,但是无法实质绑定到相关位域上,只能是被绑定到了一个相关位域的临时副本上。