【C++】 ——小白视角C++11中的右值引用

右值引用

在本篇你将看到:

  • 什么是左值?什么是右值?
  • 什么是左值引用?什么是右值引用?
  • 什么是移动构造?

1、左值和右值

左值和右值是C语言的概念,但是C语言并没有给出严格的区分方式,一般认为:可以放在等号左边的或者能够取地址的称为左值,只能放在等号右边的,或者不能取地址称为右值。但是也不一定完全正确。

咱们先来看一段代码:

int main()
{
	int a = 10;
	int b = 20;

	//a和b都是左值,b既可以在=的左侧,也可以在右侧,如下:
	a = b;
	b = a;
	//说明:左值既可以放在=的左侧,也可以放在=的右侧

	const int c = 30;
	c = a;  //编译报错,c为const 常量,只允许读不允许修改
	
	 //因为可以对c取地址,因此c严格的来说不算是左值,如下:
	cout << &c << endl;

	//编译失败,因为b+1的结果是一个临时变量,没有具体名称,不能取地址,因此为右值,如下:
	b + 1 = 20;

	
	system("pause");
	return 0;
}

看到这里,你是否对左值和右值有一点点感觉?其实可以这么理解:对于一个表达式,凡是对其取地址(&)操作可以成功的都是左值,否则就是右值

需要注意的是:临时对象是右值

总结:

1、普通类型的变量,因为有名字,可以取地址,都认为是左值
2、const修饰的常量,不可修改,制度类型的,理论按照右值俩对待,但是因为其可以取地址,C++11认为它是左值
3、如果表达式的运行结果是一个临时对象或者对象,认为是右值
4、如果表达式运行结果或者单个变量是一个引用,则认为是左值

2、左值引用和右值引用

了解左值和右值之后,我们再来说说左值引用和右值引用。我们知道C++11是不能对右值进行修改,但是右值引用的出现打破了这一格局,它允许我们获取右值的引用并修改它。

看一个代码秒懂:

int main()
{
	int a = 10;
	//普通类型只能引用左值,不能引用右值,如下:
	int& ra1 = a;   //ral为a的别名
	//int& ra2 = 10;  //编译失败,因为10是右值

	//const引用既可以引用左值,也可以引用右值,如下:
	const int& ra3 = 10;
	const int& ra4 = a;
	system("pause");
	return 0;
}

一句话概括:普通类型只能引用左值,不能引用右值,但是const引用既可以引用左值,也可以引用右值

右值引用的类型为:类型 && a=被修改的对象。如下:

int main()
{
	//10本来是纯右值,本来是一个符号,没有具体空间
	//右值引用变量r1在定义过程中,编译器产生了一个临时变量,r1实际引用的是临时变量
	int &&r1 = 10;
	r1 = 100;

	int a = 10;
	//int&& r2 = a;  //编译失败,因为右值引用不能引用左值
	int&& r3=move(a);  //但是加上move之后可以引用左值
	return 0;
}

总结:

  • 左值引用和右值引用都是给对象取别名
  • 左值通常是:可以被修改的对象
  • 右值通常是:常量,表达式的返回值
  • 左值可以引用左值
  • const左值可以引用右值
  • 右值可以引用右值
  • 右值引用可以用move来引用左值

3、拷贝构造函数的局限性

(为什么突然提到拷贝构造函数,因为移动构造可以解决拷贝构造的不足)在这里我定义了一个类Test,然后在main函数里面调用Test的构造函数和拷贝构造函数初始化Test 的对象t。
在这里插入图片描述
解释一下,可以看到,这个例子中调用了两次拷贝构造,一次是类外调用Test的构造函数,返回给Function函数的时候,一次是初始化Test对象t的时候。
其实这两个临时对象并没有什么意义,构造结束就会被销毁,也就是一个将亡值,在拷贝构造中进行了不必要的拷贝,在以上代码还好,我只开了一百个int的空间,那万一是几百万个甚至是几亿个,效率就会更低。好像有点道理,那我们应该怎么办?看后面

4、移动构造函数

移动构造是想,既然你(临时对象)已经是个将亡值了,那我直接那你的内存拿来,你也就不用再开空间慢慢的把你的数据拷贝给我,也就是说直接上述代码中我们直接把_a所指向的那块内存拿过来,然后把之前的100个整型值给复制过来。其实这就是移动构造函数的思想

关于移动构造函数,就是一种构造函数,不过它所接受的参数是一个本类对象的右值引用,对于以上例子,它的移动构造函数如下:

Test(Test &&rhs):_a(rhs._a)
{
	rhs._a=nullptr;
}

在移动构造的初始化列表的时候,我们只做了一个浅拷贝,_a(rhs._a),将rhs对象已经申请的内存占用了,同时将rhs的指针赋值为nullptr,这就避免了拷贝构造函数内存复制导致的效率问题。

以上就是关于C++右值引用的信息,笔者也是才学不久,哪里有问题,希望广大网友提出,一定虚心接受

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值