【C++11】右值引用和移动语义

一.左值和右值的定义

  1. 左值在进程的虚拟地址空间中有确定的地址,是存储在内存中的,可以被取地址,
    可以出现在赋值符号的左右两边
  2. 右值可能只是寄存器中的,或者被编译器优化掉,并没有内存地址,所以不能被取地址,只能出现在赋值符号的左边

二. 左值引用和右值引用

Type& r1 = x; Type&& rr1 = y;

  1. 在语法上,左值引用就用就是给左值取别名,右值引用就用就是给右值取别名
  2. 左值引用不能引用右值,但是const左值可以引用右值
  3. 右值不能直接引用左值,但是可以引用move(左值)
  4. 右值引用表达式的属性是左值,可以被取地址

思考:引用的底层就是指针,如果说右值只是存在寄存器中,那右值引用是如何实现给右值取别名的呢?
绑定到右值引用时,编译器会强制为临时对象分配内存,这样右值引用被取地址指向的地址就是这个被分配的内存

三. 引用延长生命周期

右值引用可用于延长临时对象的生命周期,const左值也可以,但是const的值不能被修改

 std::string s1 = "Test";
 std::string&& r1 = s1;     //错误,右值引用不能绑定左值  
 const std::string& r2 = s1 + s1;     
 r2 += "Test";  //错误:const后的值不能被修改               
 std::string&& r3 = s1 + s1;   //右值引⽤延⻓⽣存期       
 r3 += "Test";          //不加const的右值引用可以被修改              

四. 左值和右值的参数匹配

  1. 形参是左值只能传入左值的实参
  2. 形参是const左值时,左值右值都能传入
  3. 形参是右值时,只能传入右值

实参会找出和它最匹配的形参,比如同时有const 左值和右值时,右值的实参就会实例化出右值的那个函数

五. 右值引用的移动语义的使用场景

1.编译器的优化

语法上来说,返回一个对象的返回函数(图一)应该构造生成三个对象,这样·func()
中的ret和copy就浪费了时间和空间
但在编译器的优化下,有时会只构造一个对象
只构造main函数中的str对象,如(图二)

在这里插入图片描述

在这里插入图片描述
这样来看似乎也能解决了时间空间浪费问题,但有一种情况必须生成临时对象
(如图三),str是个已经存在的对象,无法构造优化,必须对str进行深拷贝
而c++11提供的移动构造和移动赋值就完美解决了这个个问题
在这里插入图片描述

2.移动构造和移动赋值

移动构造移动赋值本质上就是掠夺右值对象的资源,上文我们说了,右值对象的生命周期只在当前行,无法被取地址,但右值引用的表达式属性是左值,可以被取地址,对程序来说,出了右值的当前行这个资源就没用了,可以被掠夺,所以在实现移动构造移动赋值时,可以直接交换资源,被赋值或拷贝的对象原来的资源交给右值,随右值的生命周期销毁,被返回的对象资源始终只有一份,这样不管编译器是否优化都不会产生多余的拷贝了
下面是string类的移动赋值和移动构造的简单实现

在这里插入图片描述

// 移动赋值
	string& operator=(string&& s)
{
	std::cout << "string& operator=(string&& s) -- 移动赋值" <<std:: endl;
	swap(s);
	return *this;
}
// 移动构造
	string(string&& s)
	{
		std::cout << "string(string&& s) -- 移动构造" << std::endl;
		swap(s);
	}

3.右值移动和移动语义在传参中的提效

  1. 查看STL文档,C++11后大多容器的insert和push接口都提供了右值版本的接口
  2. 当实参是⼀个左值时,容器内部继续调用拷贝构造进行拷贝,将对象拷贝到容器空间中的对象
  3. 当实参是⼀个右值,容器内部则调用移动构造,右值对象的资源到容器空间的对象上
  4. emplace系列地接口都是右值引用版本的,还涉及到可变参数,同样是C++11的知识,可以看后续讲解
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值