🌏博客主页: 主页
   🔖系列专栏: C++
  ❤️感谢大家点赞👍收藏⭐评论✍️ 
  😍期待与大家一起进步!
文章目录
- 一、左值与右值
- 二、 引用总结:
- 1.左值:
- 2.右值:
 
- 三、左值引用的优缺:
- 四、移动拷贝
- 1.铺垫知识
- 2.原理:
 
- 五、 源码
一、左值与右值
左值是一个表示数据的表达式(如变量名或解引用的指针),我们可以获取它的地址+可以对它赋值,左值可以出现赋值符号的左边,右值不能出现在赋值符号左边。定义时const修饰符后的左值,不能给他赋值,但是可以取它的地址。左值引用就是给左值的引用,给左值取别名。
右值也是一个表示数据的表达式,如:字面常量、表达式返回值,函数返回值(这个不能是左值引用返回)等等,右值可以出现在赋值符号的右边,但是不能出现出现在赋值符号的左边,右值不能取地址。右值引用就是对右值的引用,给右值取别名。
二、 引用总结:
1.左值:
- 左值引用只能引用左值,不能引用右值。
- 但是const左值引用既可引用左值,也可引用右值
 	int a = 10;
    int& ra1 = a;   // ra为a的别名
    //int& ra2 = 10;   // 编译失败,因为10是右值
    // const左值引用既可引用左值,也可引用右值。
    const int& ra3 = 10;
    const int& ra4 = a; 
2.右值:
- 右值引用只能右值,不能引用左值。
- 但是右值引用可以move以后的左值。
// 右值引用只能右值,不能引用左值。
 int&& r1 = 10;
 
 // error C2440: “初始化”: 无法从“int”转换为“int &&”
 // message : 无法将左值绑定到右值引用
 int a = 10;
 int&& r2 = a;
 
 // 右值引用可以引用move以后的左值
 int&& r3 = std::move(a);
三、左值引用的优缺:
 优点:做参数和返回值都可以提高效率。
 缺点:当函数返回对象是一个局部变量,出了函数作用域就不存在了,就不能使用左值引用返回,只能传值返回。
 
 但这里传值返回又有一个问题,那就是效率很低,而且我进行的都是深拷贝,根据编译器的不同,有可能会进行两次拷贝构造。
 
 
四、移动拷贝
1.铺垫知识
在讲解移动拷贝之前我们先来引入几个概念:
 内置类型的右值:纯右值
 自定义类型的右值:将亡值(因为我们自定义类型,那上面的s=func()来说,过了这一行后,我返回的func就要被销毁了,一般生命周期只有一行)
在const左值引用与右值引用都存在的情况下,我们给右值起别名,编译器会走更匹配的
 
2.原理:
移动构造本质是将参数右值的资源窃取过来,占位已有,那么就不
 用做深拷贝了,所以它叫做移动构造,就是窃取别人的资源来构造自己。
string(string&& s)
			:_str(nullptr)
		{
			cout << "string(string&& s) -- 移动拷贝" << endl;
			swap(s);
			//因为这里我们用的右值引用,
			//我们传值返回的时候会将str识别为将亡值
			//因为它满足将亡值的特性,过了return以后就被销毁了
			//既然你反正都要销毁,不如和我交换一下
		}
string& operator=(string&& s)
		{
			cout << "string& operator=(string && s) -- 移动拷贝" << endl;
			swap(s);
			return *this;
		}

 
这里没有调用深拷贝的拷贝构造,而是调用了移动构造,移动构造中没有新开空间,拷贝数据,所以效率提高了。
五、 源码
这里为了方便看,所以删除了一些函数,详细可以到【C++】string类的模拟实现(增删查改,比大小,运算符重载)
namespace bit
{
	class string
	{
	public:
	 
		string(const char* str = "")
			:_size(strlen(str))
			, _capacity(_size)
		{
			//cout << "string(const char* str  )--构造函数" << endl;
			_str = new char[_capacity + 1];
			strcpy(_str, str);
		}
		// s1.swap(s2)
		void swap(string& s)
		{
			::swap(_str, s._str);
			::swap(_size, s._size);
			::swap(_capacity, s._capacity);
		}
		string& operator=(string&& s)
		{
			cout << "string& operator=(string && s) -- 移动拷贝" << endl;
			swap(s);
			return *this;
		}
		 
		string( string&& s)
			:_str(nullptr)
		{
			cout << "string(string&& s) -- 移动拷贝" << endl;
			swap(s);
			//因为这里我们用的右值引用,
			//我们传值返回的时候会将str识别为将亡值
			//因为它满足将亡值的特性,过了return以后就被销毁了
			//既然你反正都要销毁,不如和我交换一下
		}
		string(const string& s)
			:_str(nullptr)
		{
			cout << "string(const string& s) -- 深拷贝" << endl;
			string tmp(s._str);
			swap(tmp);
		}
		// 赋值重载
		string& operator=(const string& s)
		{
			cout << "string& operator=(string s) -- 深拷贝" << endl;
			string tmp(s);
			swap(tmp);
			return *this;
		}
		 
		~string()
		{
			delete[] _str;
			_str = nullptr;
		}
  
	private:
		char* _str;
		size_t _size;
		size_t _capacity; // 不包含最后做标识的\0
	};
}












![[Python进阶] Pyinstaller打包程序时为程序添加图标](https://img-blog.csdnimg.cn/ce7bded798394ff39b16e74e01ce0eb4.png)






