右值引用与移动构造详解

右值引用与移动构造

  • 这节我们来详细的介绍一下什么是左值引用,什么是右值引用,以及为什么要引入右值引用,还有就是c++11非常重要的特性 -> 移动构造

左值引用和右值引用

左值是一个表示数据的表达式(如变量名或解引用的指针),我们可以获取它的地址+可能可以对它赋值,左值可以出现赋值符号的左边,右值不能出现在赋值符号左边。定义时const修饰符后的左 值,不能给他赋值,但是可以取它的地址。左值引用就是给左值的引用,给左值取别名。左值引用与右值引用一样,一旦引用了一个对象就不能再引用另外一个对象

右值也是一个表示数据的表达式,如:字面常量、表达式返回值,函数返回值(这个不能是左值引 用返回)等等,右值可以出现在赋值符号的右边,但是不能出现出现在赋值符号的左边,右值不能 取地址。右值引用就是对右值的引用,给右值取别名。这里注意,右值出了字面常量以外,都可以理解是一些临时变量 -> 非左值引用返回值之类的

  • 注:这里有一个很容易混淆的点,就是右值引用引用的是一个右值,但是这个变量本身是一个左值
int main()
{
 double x = 1.1, y = 2.2;
 int&& rr1 = 10;
 const double&& rr2 = x + y;
 rr1 = 20;
 cout << &rr1 << endl;
 rr2 = 5.5;  // 报错

 return 0;
}
  • 这里的rr1是一个左值,它是可以取出地址的,然后rr1=20不是重新绑定一个右值,而是修改其所绑定的右值。

右值引用的使用场景

  • 为什么要引入右值引用 -> 为了解决一些左值引用没有完全解决的问题

​ 左值引用解决了传参,和传值返回的问题,但是对于传值返回的问题没有完全解决

->如果返回的是一个局部作用域的对象就不能使用引用返回,但是使用传值返回的话就会进行一份深拷贝,这对于追求极值性能的c++来说不是很可取,所以因右值引用而产生的移动构造就起了作用,它可以很好的解决传值返回深拷贝的问题

  • 为什么:因为右值引用往往是临时变量,临时变量一般出了作用域就会进行销毁,那既然你都要销毁了,如果我还要照着你的资源进行一份深拷贝岂不是太浪费了,所以我们可以使用移动构造 -> 其实就是进行资源的转移,将原来要销毁的值转移给要拷贝的值。

对于下面的代码

	bit::string to_string(int value)
	{
		bool flag = true;
		if (value < 0)
		{
			flag = false;
			value = 0 - value;
		}
		bit::string str;

		while (value > 0)
		{
			int x = value % 10;
			value /= 10;
			str += ('0' + x);
		}

		if (flag == false)
		{
			str += '-';
		}

		std::reverse(str.begin(), str.end());

		return str;
	}


	int main()
	{
		bit::string s1;
		s1 = bit::to_string(1234);

		return 0;
	}

如果没有移动构造的话,结果是这样的

candy:~/code/cpp/test/grammar $  ./demo.exe 
string(char* str)
string(char* str)
string(const string& s) -- 深拷贝
string& operator=(const string& s) -- 深拷贝

​ 这是在没有编译器优化的情况下,如果有优化会把这次拷贝构造(这是将str拷贝给临时对象用的)去除掉,只剩一次赋值,但还是深拷贝,性能并不高。

移动构造

		// 移动构造
		// 临时创建的对象,不能取地址,用完就要消亡
		// 深拷贝的类,移动构造才有意义
		string(string&& s)
		{
			cout << "string(string&& s) -- 移动拷贝" << endl;
			swap(s);
		}
		
				//移动赋值
		string& operator=(string&& s)
		{
			cout << "string& operator=(string&& s) -- 移动拷贝" << endl;

			swap(s);
			return *this;
		}

​ 通过对移动构造和赋值的观察我们可以知道,这就是对一个右值(将亡值)进行资源的交换,这样就可以避免深拷贝,从而大大的提高效率

candy:~/code/cpp/test/grammar $  ./demo.exe 
string(char* str)
string(char* str)
string(string&& s) -- 移动拷贝
string& operator=(string&& s) -- 移动拷贝

这是有移动构造的结果

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值