• C++11右值引用



    在这里插入图片描述

    1.右值引用和移动语义

    1.1左值引用和右值引用

    之前我们对左右值比较浅显的概念是:左值可以修改 右值不可以修改
    接下来我们会对左右值有进一步的理解:左值可以取地址

    1. 无论左值引用还是右值引用,都是给对象取别名
    2. 左值是一个表示数据的表达式(如变量名或解引用的指针),我们可以获取它的地址+可以对它赋值,左值可以出现赋值符号的左边,右值不能出现在赋值符号左边。定义时const修饰符后的左值,不能给他赋值,但是可以取它的地址。左值引用就是给左值的引用,给左值取别名。
    int main()
    {
    	//变量名
    	int b = 0;
    	int* pb = &b;         //左值可以取地址
    	int& rb = b;          //左值引用
    
    	//指针
    	int* p = new int(1);  //*p也是一个左值
    	int*& rp = p;
    	int& pvalue = *p;     //左值引用
    
    	//const后的左值
    	const int c = 2;
    	const int* pc = &c;
    	//c = 20;             //不是所有的左值都可被修改 但是可以进行&操作
    	const int& rc = c;    //左值引用
    
    	//左值在=左右都可以出现
    	int d = c;
    	
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    1. 右值也是一个表示数据的表达式,如:字面常量、表达式返回值,函数返回值(这个不能是左值引用返回)等等,右值可以出现在赋值符号的右边,但是不能出现出现在赋值符号的左边,右值不能取地址。右值引用就是对右值的引用,给右值取别名
    double getmin(double a, double b)
    {
    	return a < b ? a : b;
    }
    double& Getmin(double a, double b)
    {
    	return a < b ? a : b;
    }
    int main()
    {
    	double x = 1.1, y = 2.2;
    	// 以下几个都是常见的右值
    	10;           //字面常量
    	x + y;        //表达式返回值[此返回值有空间]
    	getmin(x, y); //函数返回值[非左值引用返回]
    
    	//右值引用
    	int&& rr1 = 10;
    	double&& rr2 = x + y;
    	double&& rr3 = getmin(x, y);
    
    	//编译报错 -- 右值不可修改 右值不可放在=左边 -- 表达式必须是可修改的左值
    	10 = 1;
    	x + y = 1;
    	getmin(x, y) = 1; 
    	Getmin(x, y) = 1; //左值引用返回不报错
    
    	//表达式必须为左值或函数指示符 -- 右值不能取地址
    	&10;
    	&(x + y);
    	&getmin(x, y);
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    1. 右值引用特殊场景[不重要 了解即可]
    int main()
    {
    	//不能取字面量10的地址,但是rr1引用后,可以对rr1取地址,也可以修改rr1
    	double x = 1.1, y = 2.2;
    	int&& rr1 = 10;
    	const double&& rr2 = x + y;
    	
    	rr1 = 20;
    	rr2 = 5.5;  // 报错
    	
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    1. 左值引用和右值引用

    左值引用只能引用左值,不能引用右值 非得引用右值 可以使用const左值引用
    右值引用只能引用右值,不能引用左值 非得引用左值 可以引用move后的左值

    int main()
    {
    	int a = 0;
    	int b = 1;
    
    	// 左值引用给左值取别名
    	int& ref1 = a;
    
    	// 左值引用给右值取别名需要加const 保持权限一致
    	const int& ref2 = (a + b);
    
    	// 右值引用给右值取别名
    	int&& ref3 = (a + b);
    
    	// 右值引用给move后左值取别名
    	int&& ref4 = move(a);
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    1.2右值引用使用场景

    区分传过来的参数是左值还是右值

    1.string为例介绍

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

    //void func(const int& a)
    //{
    //	cout << "void func(int& a) or void func(int&& a)" << endl;
    //}
    
    void func(int& a)
    {
    	cout << "void func(int& a)" << endl;
    }
    
    void func(int&& a)
    {
    	cout << "void func(int&& a)" << endl;
    }
    
    int main()
    {
    	int a = 0;
    	int b = 1;
    
    	func(a);     //传左值
    	func(a + b); //传右值
    
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    在string类里面的应用

    int main()
    {
    	string s1("hello"); 
    	string s2("world");
    
    	//左右值拷贝
    	string s3 = s1;      //左值拷贝:不能修改s1的内容  s3和s1相互独立 这也是之前我们模拟实现为什么要搞深拷贝
    	string s4 = s1 + s2; //右值拷贝:一个临时对象 具有常性 s1 + s2这个表达式的返回值所形成的临时对象 和s1\s2没有关系 
    	                     //我们可以进行资源转移 而不再进行深拷贝
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在模拟实现string类里进一步探索右值引用
    普通拷贝参数const string& 既可引用左值又可引用右值
    移动拷贝构造只可引用右值
    右值传参调用移动拷贝构造而不调用普通拷贝构造:编译器调用最匹配的那个

    在这里插入图片描述

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

    在这里插入图片描述

    代码示例

    //模拟实现string类
    namespace ape
    {
    	class string
    	{
    	public:
    		//迭代器
    		typedef char* iterator;
    		iterator begin()
    		{
    			return _str;
    		}
    
    		iterator end()
    		{
    			return _str + _size;
    		}
    
    		//构造函数
    		string(const char* str = "")
    			:_size(strlen(str))
    			, _capacity(_size)
    		{
    			_str = new char[_capacity + 1];
    			strcpy(_str, str);
    		}
    
    		//交换内容
    		void swap(string& s)
    		{
    			::swap(_str, s._str);
    			::swap(_size, s._size);
    			::swap(_capacity, s._capacity);
    		}
    
    		//拷贝构造
    		string(const string& s)
    			:_str(nullptr)
    		{
    			cout << "string(const string& s) -- 左值深拷贝" << endl;
    
    			string tmp(s._str);
    			swap(tmp);
    		}
    
    		// 移动构造: 传过来的s[即 (s1 + '!')]是右值
    		//ape::string ret2 = (s1 + '!'); 右值拷贝 ret2.string( (s1 + '!') );
    		string(string&& s)
    			:_str(nullptr)
    		{
    			cout << "  string(string&& s)    -- 右值移动拷贝" << endl;
    			swap(s); //直接换过来
    		}
    
    		// 赋值重载
    		string& operator=(const string& s)
    		{
    			cout << "string& operator=(string s) -- 深拷贝" << endl;
    			string tmp(s);
    			swap(tmp);
    
    			return *this;
    		}
    
    		//析构函数
    		~string()
    		{
    			delete[] _str;
    			_str = nullptr;
    		}
    
    		//重载下标运算符[]
    		char& operator[](size_t pos)
    		{
    			assert(pos < _size);
    			return _str[pos];
    		}
    
    		//扩容
    		void reserve(size_t n)
    		{
    			if (n > _capacity)
    			{
    				char* tmp = new char[n + 1];
    				strcpy(tmp, _str);
    				delete[] _str;
    				_str = tmp;
    
    				_capacity = n;
    			}
    		}
    
    		//尾插
    		void push_back(char ch)
    		{
    			if (_size >= _capacity)
    			{
    				size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;
    				reserve(newcapacity);
    			}
    
    			_str[_size] = ch;
    			++_size;
    			_str[_size] = '\0';
    		}
    
    		//+=运算符重载
    		string& operator+=(char ch)
    		{
    			push_back(ch);
    			return *this;
    		}
    
    		//+号运算符重载 不改变this 返回新string
    		string operator+(char ch)
    		{
    			cout << "operator+:";
    			string tmp(*this);
    			tmp += ch;
    			return tmp;
    		}
    
    		//c_str函数
    		const char* c_str() const
    		{
    			return _str;
    		}
    	private:
    		char* _str;
    		size_t _size;
    		size_t _capacity; 
    	};
    
    }
    
    //整形变字符串
    ape::string int_to_string(int value)
    {
    	bool flag = true;
    	if (value < 0)
    	{
    		flag = false;
    		value = 0 - value;
    	}
    	ape::string str;
    	while (value > 0)
    	{
    		int x = value % 10;
    		value /= 10;
    		//数字变字符
    		str += (x + '0' );
    	}
    	if (flag == false)
    		str += '-';
    	reverse(str.begin(), str.end());
    	return move(str);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158

    库里的移动构造

    在这里插入图片描述

    s1是个左值 move函数的返回值被识别为右值 – 调用移动构造 s3的内容[啥也没有]给了s1 s1的内容给了s3

    2.其他容器在C++11后的构造函数

    在这里插入图片描述

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

    2.容器的插入函数

    2.1list

    在这里插入图片描述

    2.2map

    在这里插入图片描述

    3.左值引用/右值引用的总结

    左值引用通过引用直接操作 省去中间额外的拷贝
    右值引用通过识别是左值还是右值 如果是右值 直接移动拷贝

    4.完美转发

    4.1首先看右值引用的特例

    在这里插入图片描述

    首先我们需要思考 C++11为什么要大费周折搞出一个右值引用? 右值引用的意义何在? 右值引用的初衷是啥?

    显而易见,通过上述的讨论 我们知道 数据分为左值和右值 当涉及到容器的深层拷贝时 左值需要做深层拷贝[不动原数据 将原数据拷贝给新对象] 但是右值是一个临时变量 具有常性 当作用域完结 他的值也就消失 即所谓的"将亡值" 为了最大化提升C++语法的优势 大佬搞出了一个叫右值引用的东西 其目的就在于当数据为右值时 直接把该数据的资源转移到新对象上 而不管你这个临时对象被转移后会发生什么 因为你是个临时变量 程序结束自动销毁 但是上述代码又显示出了一个新的问题 当右值引用 引用了所传的参数 该引用的属性变为了左值

    为什么要改成左值呢?

    因为右值引用的初衷就是当参数时右值 可以直接进行资源转移 要想转移 此引用的属性就需要时左值

    由此引发了新的问题 如下代码的输出违背了代码的本意

    void Fun(int& x) 
    { 
    	cout << "左值引用" << endl; 
    }
    void Fun(const int& x) 
    { 
    	cout << "const 左值引用" << endl; 
    }
    
    void Fun(int&& x) 
    { 
    	cout << "右值引用" << endl;
    }
    void Fun(const int&& x)
    { 
    	cout << "const 右值引用" << endl;
    }
    
    //万能引用/引用折叠:既可以引用左值 又可以引用右值
    template<typename T>
    //这里是一个右值引用 当这个函数被调用 t是参数的右值引用 但是此时 t的属性变为了左值
    void PerfectForward(T&& t)
    {
    	//Fun(forward(t));
    	Fun(t);
    }
    
    int main()
    {
    	PerfectForward(10);           // 右值
    
    	int a;
    	PerfectForward(a);            // 左值
    	PerfectForward(move(a));      // 右值
    
    	const int b = 8;
    	PerfectForward(b);		      // const 左值
    	PerfectForward(move(b));      // const 右值
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    由于t的属性成为左值 所以不管你原来是左值还是右值 都会调用左值的代码
    在这里插入图片描述

    怎么办?怎么解决?好不容易搞出来的右值引用难不成要抛弃?解决办法见下:

    在这里插入图片描述
    此时 代码的本意达到 提示:这里的forward(t) 作用在于将t的属性置为原有属性 当原有属性为左值 你还是左值 是右值 你还是右值 当需要把原有属性是右值但是在该函数需要当成左值来用时 不加forward(t) 即可

    4.2接着看完美转发的应用场景

    1.详细图解

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    2.完整代码

    List.h
    #pragma once
    #define _CRT_SECURE_NO_WARNINGS 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    using namespace std;
    
    namespace ape
    {
    	//结点类---右值引用结点构造函数 
    	template<class T>
    	struct list_node
    	{
    		list_node<T>* _next;
    		list_node<T>* _prv;
    		T _data;
    		list_node(const T& x = T())
    			:_next(nullptr)
    			, _prv(nullptr)
    			, _data(x)
    		{
    		
    		}
    		list_node(T&& x = T())
    			:_next(nullptr)
    			, _prv(nullptr)
    			, _data(forward<T>(x))
    		{
    		
    		}
    	};
    
    	//迭代器类
    	template<class T, class Ref, class Ptr>
    	struct __list_iterator
    	{
    		typedef list_node<T> node;
    		typedef __list_iterator<T, Ref, Ptr> self;
    		node* _node;
    
    		__list_iterator(node* n)
    			:_node(n)
    		{
    		}
    
    		Ref operator*()
    		{
    			return _node->_data;
    		}
    
    		Ptr operator->()
    		{
    			return &_node->_data;
    		}
    
    		self& operator++()
    		{
    			_node = _node->_next;
    
    			return *this;
    		}
    
    		self operator++(int)
    		{
    			self tmp(*this);
    			_node = _node->_next;
    
    			return tmp;
    		}
    
    		self& operator--()
    		{
    			_node = _node->_prv;
    
    			return *this;
    		}
    
    		self operator--(int)
    		{
    			self tmp(*this);
    			_node = _node->_prv;
    
    			return tmp;
    		}
    
    		bool operator!=(const self& s)
    		{
    			return _node != s._node;
    		}
    
    		bool operator==(const self& s)
    		{
    			return _node == s._node;
    		}
    	};
    
    	//链表类
    	template<class T>
    	class list
    	{
    		typedef list_node<T> node;
    	public:
    		typedef __list_iterator<T, T&, T*> iterator;
    		typedef __list_iterator<T, const T&, const T*> const_iterator;
    		iterator begin()
    		{
    			return iterator(_head->_next);
    		}
    		const_iterator begin() const
    		{
    			return const_iterator(_head->_next);
    		}
    		iterator end()
    		{
    			return iterator(_head);
    		}
    		const_iterator end() const
    		{
    			return const_iterator(_head);
    		}
    
    		//无参构造
    		list()
    		{
    			_head = new node(T());
    			_head->_next = _head;
    			_head->_prv = _head;
    		}
    
    		//迭代器区间构造
    		template <class Iterator>
    		list(Iterator first, Iterator last)
    		{
    			_head = new node(T());
    			_head->_next = _head;
    			_head->_prv = _head;
    
    			while (first != last)
    			{
    				push_back(*first);
    				++first;
    			}
    		}
    
    		//交换内容
    		void swap(list<T>& tmp)
    		{
    			std::swap(_head, tmp._head);
    		}
    		//拷贝构造
    		list(const list<T>& lt)
    		{
    			_head = new node(T());
    			_head->_next = _head;
    			_head->_prv = _head;
    
    			list<T> tmp(lt.begin(), lt.end());
    			swap(tmp);
    		}
    
    		//赋值运算符重载
    		list<T>& operator=(list<T> lt)
    		{
    			swap(lt);
    			return *this;
    		}
    
    		//析构函数
    		~list()
    		{
    			clear();
    			delete _head;
    			_head = nullptr;
    		}
    
    		//清空函数
    		void clear()
    		{
    			iterator it = begin();
    			while (it != end())
    			{
    				erase(it++);
    			}
    		}
    
    		//尾插 --- 右值引用尾插
    		void push_back(const T& x)
    		{
    			insert(end(), x);
    		}
    		void push_back(T&& x)
    		{
    			insert(end(), forward<T>(x));
    		}
    
    		//头插 -- 右值引用头插
    		void push_front(const T& x)
    		{
    			insert(begin(), x);
    		}
    		void push_front(T&& x)
    		{
    			insert(begin(), forward<T>(x));
    		}
    
    		//尾删
    		void pop_back()
    		{
    			erase(--end());
    		}
    
    		//头删
    		void pop_front()
    		{
    			erase(begin());
    		}
    
    		//插入函数 --- 右值引用插入
    		void insert(iterator pos, const T& x)
    		{
    			node* cur = pos._node;
    			node* prev = cur->_prv;
    
    			node* new_node = new node(x);
    
    			prev->_next = new_node;
    			new_node->_prv = prev;
    			new_node->_next = cur;
    			cur->_prv = new_node;
    		}
    		void insert(iterator pos, T&& x)
    		{
    			node* cur = pos._node;
    			node* prev = cur->_prv;
    
    			node* new_node = new node(forward<T>(x));
    
    			prev->_next = new_node;
    			new_node->_prv = prev;
    			new_node->_next = cur;
    			cur->_prv = new_node;
    		}
    
    		//删除函数
    		iterator erase(iterator pos)
    		{
    			assert(pos != end());
    
    			node* prev = pos._node->_prv;
    			node* next = pos._node->_next;
    
    			prev->_next = next;
    			next->_prv = prev;
    			delete pos._node;
    
    			return iterator(next);
    		}
    	private:
    		node* _head;
    	};
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    String.h
    #pragma once
    #define _CRT_SECURE_NO_WARNINGS 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    using namespace std;
    
    namespace ape
    {
    	class string
    	{
    	public:
    		//迭代器
    		typedef char* iterator;
    		iterator begin()
    		{
    			return _str;
    		}
    
    		iterator end()
    		{
    			return _str + _size;
    		}
    
    		//构造函数
    		string(const char* str = "")
    			:_size(strlen(str))
    			, _capacity(_size)
    		{
    			_str = new char[_capacity + 1];
    			strcpy(_str, str);
    		}
    
    		//交换内容
    		void swap(string& s)
    		{
    			::swap(_str, s._str);
    			::swap(_size, s._size);
    			::swap(_capacity, s._capacity);
    		}
    
    		//拷贝构造
    		string(const string& s)
    			:_str(nullptr)
    		{
    			cout << "string(const string& s) -- 左值深拷贝" << endl;
    
    			string tmp(s._str);
    			swap(tmp);
    		}
    
    		// 移动构造: 传过来的s[即 (s1 + '!')]是右值
    		//ape::string ret2 = (s1 + '!'); 右值拷贝 ret2.string( (s1 + '!') );
    		string(string&& s)
    			:_str(nullptr)
    		{
    			cout << "  string(string&& s)    -- 右值移动拷贝" << endl;
    			swap(s); //直接换过来
    		}
    
    		// 赋值重载
    		string& operator=(const string& s)
    		{
    			cout << "string& operator=(string s) -- 深拷贝" << endl;
    			string tmp(s);
    			swap(tmp);
    
    			return *this;
    		}
    
    		//析构函数
    		~string()
    		{
    			delete[] _str;
    			_str = nullptr;
    		}
    
    		//重载下标运算符[]
    		char& operator[](size_t pos)
    		{
    			assert(pos < _size);
    			return _str[pos];
    		}
    
    		//扩容
    		void reserve(size_t n)
    		{
    			if (n > _capacity)
    			{
    				char* tmp = new char[n + 1];
    				strcpy(tmp, _str);
    				delete[] _str;
    				_str = tmp;
    
    				_capacity = n;
    			}
    		}
    
    		//尾插
    		void push_back(char ch)
    		{
    			if (_size >= _capacity)
    			{
    				size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;
    				reserve(newcapacity);
    			}
    
    			_str[_size] = ch;
    			++_size;
    			_str[_size] = '\0';
    		}
    
    		//+=运算符重载
    		string& operator+=(char ch)
    		{
    			push_back(ch);
    			return *this;
    		}
    
    		//+号运算符重载 不改变this 返回新string
    		string operator+(char ch)
    		{
    			cout << "operator+:";
    			string tmp(*this);
    			tmp += ch;
    			return tmp;
    		}
    
    		//c_str函数
    		const char* c_str() const
    		{
    			return _str;
    		}
    	private:
    		char* _str;
    		size_t _size;
    		size_t _capacity;
    	};
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    Test.cpp
    #define _CRT_SECURE_NO_WARNINGS 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    using namespace std;
    
    
    
    #include "List.h"
    #include "String.h"
    
    int main()
    {
    	ape::list<ape::string> lt;
    
    	ape::string s1("hello world");
    	lt.push_back(s1);
    
    	lt.push_back(ape::string("hello world"));
    	lt.push_back("hello world");
    
    	return 0;
    }
    
    
    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
  • 相关阅读:
    I3D 简介
    CSS:字体和文本样式
    OpenHarmony应用程序包整体说明
    【Mindspore】GeneratorDataset 中source data 含有dict 应该如何处理
    Eclipse 主网即将上线迎空投预期,Zepoch 节点或成受益者?
    K8S哲学 - probe 探针
    Leetcode_3:无重复字符的最长子串
    恶补《操作系统》2_1——王道学习笔记
    视频截取gif动画怎么操作?轻松一键快速视频转gif
    大数据基础
  • 原文地址:https://blog.csdn.net/LHRan_ran_/article/details/133823688