栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C++基础第4章:表达式基础(1)——引入、左值和右值

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C++基础第4章:表达式基础(1)——引入、左值和右值

文章目录
  • 1.引入
  • 2.左值与右值
    • 2.1.左值与右值的概念
    • 2.2.C++中各种左值和右值的概念
    • 2.3.理解左值和右值
    • 2.4.左值与右值的转换
    • 2.5.再论decltype

1.引入

2.左值与右值

2.1.左值与右值的概念

注意左值和右值的概念是相对于赋值表达式的=来说的,对于一个对象或者数值,不能说它是左值还是右值,就没有这种说法。而是应该把这个对象或者数值带入到复制表达式中,说它在这个表达式中是左值还是右值。

int x;   // 这里不能说它是左值还是右值
x = 3;   // 在这个表达式中,x是左值,3是右值
2.2.C++中各种左值和右值的概念

首先明确,下面所说的求值的概念并不是通常所说的把变量的值是多少拿出来,而更像是确定某个量的本质是什么;比如对泛左值求值,得到的是它所关联的那块内存;对纯右值求值,得到的可能就是某个运算符的操作数。

  1. glvalue(泛左值):首先它是一个表达式,它的求值结果是一个对象、位域(对象在内存中的哪个位)或者函数。比如对于语句x = 3,首先对x求值,再对3求值,然后再赋值。这里对x求值实际上不是真的对x求值看它里面存储的数值是多少,本质上是确定x所关联的内存。
  2. prvalue(纯右值):和泛左值相对应,首先它也是一个表达式,它的求值结果是一下两个之一:
  • 它作为某个运算符的操作数,比如x=3中=是一个运算符,其中的3只能被当做操作数,因为不能写成3=x,也就是它不能作为这个运算符的赋值对象。再比如3+2,其中3和2都是操作数。
  • 它用来初始化某个对象或者位域。比如语句int x = 3,这里=并不是一个赋值运算符,而是代表拷贝初始化。所以这里的3就是用来初始化某个对象,而没有对应具体的标识,因为没有对应的内存来显式的表示它。
  1. xvalue(亡值):首先它是一个泛左值,然后它代表其资源能够被重新使用的对象或者位域。为了理解将亡值,这里需要先介绍右值引用的概念:
#include 
#include 

// 注意这里的两个&&代表右值引用,后面会继续讲解右值引用的操作
void fun(std::vector&& par)
{
		// 在这里面就可以对x的资源进行重复利用,因为x是将亡值,
		// 外面不会对它进行操作了
}

int main()
{
	std::vector x;
	// 使用std::move把x构造成一个将亡值,现在的x只是一个泛左值(因为它绑定了一块内存)
	fun(std::move(x));   
	
	// 上面把x转成将亡值的目的就是后面不会再对x的资源进行任何的处理,
	// 因为我们认为x是一个将亡值,是即将死亡的,所以在这里就会把x资源
	// 交出去,后面不会再对x的资源进行处理。这样在fun函数里面就可以
	// 任意操作x了
	// ....
}
2.3.理解左值和右值
  1. 左值首先是一个泛左值,也就是它是表达一个对象,绑定一块内存的。其次只要它不是一个将亡值,那么他就是一个左值。
    而右值则包括两部分, 一种是纯右值,它只能被当做操作符的操作数或者被用来初始化对象。如果它不是纯右值,那么它就是将亡值。

  2. 理解左值不一定能放在等号左边:

// 首先x绑定了一块内存,所以它是泛左值。其次后面一直可以使用它,
// 所以它不是将亡值。因此x是一个左值
const int x = 3;   

// 但是左值不一定能放在等号左边,因为x是const
x = 4;   // 错误
  1. 理解右值也可以放在等号左边:
struct Str {} ;

// 首先Str()这种写法类似匿名对象?得到的是一个纯右值,可以用它来
// 初始化对象。但是它也可以放在等号左边,下面语句的意思,就是用右边的纯右值,初始化左边的匿名对象。
Str() = Str();  
2.4.左值与右值的转换

  1. 左值转换成右值
int x = 3;  // x是左值
int y = x;  // x是左值,作为右值给y初始化
  1. 临时具体化
struct Str
{
	int x;
};

int main()
{
  // 这里单独写Str()类似一个匿名对象,它没有绑定具体哪一块内存,
  // 所以它是一个纯右值,一般用于操作数或者对象的初始化。但是这里
  // 用.操作符取其中的x,类似于把Str()这个对象具体化了,然后取它其
  // 中对应x的内存,所以这里的Str()就要把它视为将亡值,并且是属于
  // 泛左值类型的将亡值,这样才能取它其中的x对应的内存。
  // 这种就是临时具体化
	Str().x
}
2.5.再论decltype


现在重点关注decltype的实参是表达式的情况:

  1. 表达式的类型是将亡值,则产生T的右值引用:

  2. 表达式的类型是左值,则产生T的引用:注意下面的代码中,decltype((x))中x必须加(),因为这样传入的才是一个表达式,否则传入的就是变量的情况,就不符合这里的规定了。

  3. 表达式类型是纯右值,则产生T:

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1009026.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号