C++11右值引用与移动语义(左值引用与右值引用的区分,移动构造与移动拷贝构造函数,移动构造,移动赋值运算符重载)

1.左值右值的区别

左值:可以取其地址
右值:不能取其地址

int b=1;//b为左值
int*p=new int(0);//p为左值
const int c=10;//c为左值
//右值
int x=10;int y=3;
10;
x+y;//表达式计算的值
fmax(x,y);//函数返回值

2.左值引用与右值引用

左值引用:

  1. 左值引用只能引用左值,不能引用右值
  2. const修饰左值引用可以引用左值也可以引用右值
int a = 10;
int& b = a;//左值引用引用左值
const int& c = 10;//const修饰的左值引用右值

右值引用:

  1. 右值引用只能引用右值或者move后的左值。
int&& a = 10;//右值引用引用常量
int num = 4;
int&& b = std::move(num);//右值引用只能引用move后的左值

3.右值引用的使用场景

左值引用用来做参数或返回值,减少拷贝提高效率。

右值引用:
针对深拷贝的类,使用右值引用增添移动构造和移动赋值提高效率

下面的代码是简单实现了C++string库以及整数转换为字符串to_string函数实现

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<assert.h>

using namespace std;


namespace NUC
{
	class string
	{
	public:
		string(const char* str = "")
			:size(strlen(str))
			, capacity(size)
		{
			cout << "构造函数" << endl;

			_src = new char[capacity + 1];
			strcpy(_src, str);
		}
		~string()
		{
			cout << "析构函数" << endl;
			delete[] _src;
			_src = nullptr;
		}
		void swap(string &s)
		{
			::swap(_src, s._src);//全局swap  std::swap
			::swap(size, s.size);
			::swap(capacity, s.capacity);
		}
		string(const string& s)
			:_src(nullptr)
		{
			cout << "拷贝构造函数" << endl;
			string tmp(s._src);
			swap(tmp);
		}
		string& operator=(const string& s)
		{
			cout << "operator=" << endl;
			string tmp(s);
			swap(tmp);

			return *this;
		}
		string& operator+=(char ch)
		{
			push_back(ch);
			return *this;
		}
		char* begin() { return _src; }
		char* end() { return _src + size; }

		void reserve(size_t i)
		{
			if (i > capacity)
			{
				char* tmp = new char[i + 1];
				strncpy(tmp, _src, size);
				delete[]_src;
				_src = tmp;
				capacity = i;
			}
		}
		void push_back(char ch)
		{
			if (size == capacity)
			{
				size_t newcapacity = capacity == 0 ? 4 : capacity * 2;
				reserve(newcapacity * 2);
			}
			_src[size] = ch;
			_src[size + 1] = '\0';
			size++;
		}

	private:
		char*_src;
		int size;
		int capacity;
	};

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

		NUC::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;
	}
}
#include"My_string.h"

void TestString()
{
	/*NUC::string str("abc");
	str += 'd';*/
	NUC::string str2 = NUC::to_string(-123);
}

int main()
{
	TestString();
	return 0;
}

此时调用to_string时返回str时,编译器会处理为右值,此时调用拷贝构造函数,因为拷贝构造函数参数为const string& s可以引用右值

在这里插入图片描述
在这里插入图片描述

移动构造函数

C++11为了提高效率,提供了移动构造函数,移动资源

在类中添加

// 移动构造
string(string&& s)
	:_src(nullptr), size(0), capacity(0)
{
	cout << "string(string&& s) -- 移动构造" << endl;
	this->swap(s);
}

此时调用to_string时返回str时,编译器会处理为右值,此时调用移动构造函数转移资源。
在这里插入图片描述
在这里插入图片描述
两次析构函数分别析构了函数to_string里面的str以及主函数的str2对象

注意:编译器优化情况与编译器有关

移动语义(move)

在这里插入图片描述

移动赋值运算符重载

使用场景:

#include"My_string.h"

void TestString()
{
	NUC::string str1;
	str1 = NUC::to_string(-123);
}

int main()
{
	TestString();
	return 0;
}

如果没有移动赋值运算符重载时,因为str1在调用函数前已经初始化好,此时NUC::to_string(-123)会调用string& operator=(const string& s)运算符重载。
在这里插入图片描述
在这里插入图片描述
在string类中添加移动赋值

// 移动赋值 
string& operator=(string&& s)
{
	cout << "string& operator=(string&& s) -- 移动赋值" << endl;
	this->swap(s);

	return *this;
}

在这里插入图片描述
在这里插入图片描述
对比减少了临时对象生成,减少了拷贝提高了效率。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

NUC_Dodamce

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值