• C++STL——string类与模拟实现


    什么是STL

    STL(standard template libaray-标准模板库):是C++标准库的重要组成部分,不仅是一个可复用的组件库,而且是一个包罗数据结构与算法的软件框架。
    STL的六大组成:仿函数,算法,迭代器,空间配置器,容器,配接器。
    注意:
    这里我是按照功能归类讲string归类到了STL里面,如果按照发展史其实并不属于STL中的容器。
    并且从现在开始我们会更频繁的开始使用这个网站了:
    cpulspuls

    string类

    为什么要学习string呢?C语言中字符串是以‘\0’结尾的,C语言当中提供的str库函数是与字符串分开的,很可能越界访问,也不方便管理,C++主要是OOP思想(抽象”、“封装”、“继承”、“多态),所以出现了string,并且更方便增删查改。

    字符串的标准

    计算机是二进制,但是如果让我们去理解一堆0和1组成的是什么意思很难理解,所以就有了编码(计算机存值——文字符号,对应关系):
    在这里插入图片描述
    这些符号就可以组成很多东西了,比如数值,单词等等。
    如果你想储存abc,那么在内存中储存的就是

    97 98 99

    想让计算机流通全世界,那么就要支持各个国家的语言,这个时候就出现了统一码
    在UTF-8中将常用的汉字用两个字节去存储,256*256=65536。(但是这里要兼容ASCII码值所以没有这么多)
    有些生僻字需要三个或者四个字节去储存。
    UTF-16不兼容ASCII码值,起步用2个字节。
    UTF-32不兼容ASCII码值,起步用4个字节。

    但是中华文化博大精深,国内又针对函数定义了新的标准,GBK

    什么是string

    string是字符串的类,该类添加了很多接口便于操作string类。
    string在底层实际是:basic_string模板类的别名,typedef basic_string string;
    不能操作多字节和变长字节序列。
    cplusplus中是这样描述的:
    在这里插入图片描述

    string常用接口介绍

    string的初始化

    string()构造空string类的对象
    string(const char* s)用字符串初始化新构造string类的的对象
    string(const string&s)用string类对象构造新的string类对象

    这类接口是调用构造函数。

    #include 
    #include 
    using namespace std;
    
    int main()
    {
    	string s("abc");//创建string类s,给s初始化abc
    	cout << s << endl;
    	string s1;//创建string类s1,不进行初始化
    	cout << s1 << endl;
    	string s2(s);//将s拷贝到s2中
    	cout << s2 << endl;
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这里插入图片描述

    比较大小与赋值

    比较的是字符串的ASCII码值。
    这些接口都是对于运算符进行重载。
    先来看赋值:

    string& operator= (const string& str);赋值string类的对象
    string& operator= (const char* s);赋值字符串
    string& operator= (char c);赋值一个字符

    #include 
    #include 
    using namespace std;
    int main()
    {
    	string s1("abc");
    	cout << s1 << endl;
    	string s2;
    	s2 = s1;//赋值string类的对象
    	cout << s2 << endl;
    	string s3;
    	s3 = "adc";//赋值字符串
    	cout << s3 << endl;
    	s3 = 's';//赋值一个字符
    	cout << s3 << endl;
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    在这里插入图片描述
    等于,大于,小于等:
    返回值为bool,参数是引用类。
    正确返回1,错误返回0.

    #include 
    #include 
    using namespace std;
    int main()
    {
    	string s1("abc");
    	string s2("adc");
    	string s3("abc");
    	string s4("abb");
    	cout << "==:" << endl;
    	cout << (s1 == s2) << endl;
    	cout << (s1 == s3) << endl;
    	cout << "< <=:" << endl;
    	cout << (s1 < s2) << endl;
    	cout << (s1 <= s2) << endl;
    	cout << (s1 < s3) << endl;
    	cout << (s1 <= s3) << endl;
    	cout << (s1 <= s4) << endl;
    	cout << "> >=:" << endl;
    	cout << (s1 > s2) << endl;
    	cout << (s1 >= s2) << endl;
    	cout << (s1 >= s3) << endl;
    	cout << (s1 > s4) << endl;
    	cout << (s1 >= s4) << endl;
    	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

    在这里插入图片描述

    容量

    这里要注意容量和有效字符长度的区别。
    size返回字符串有效长度
    capacity返回有效容量长度

    size_t size() const;
    size_t capacity() const;

    #include 
    #include 
    using namespace std;
    int main()
    {
    	string s("qwert");
    	cout << s.size() << endl;
    	cout << s.capacity() << endl;
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    这里有一个与size功能相同的接口length。(原因是因为命名的习惯)
    在这里插入图片描述
    在这里插入图片描述
    empty检测对象是否为空字符串,空返回1,非空返回0
    clear清空对象中的有效字符串

    bool empty() const;
    void clear();

    #include 
    #include 
    using namespace std;
    int main()
    {
    	string s("qwert");
    	cout << s.empty() << endl;
    	s.clear();//这里并不改变容量大小
    	cout << s.empty() << endl;
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里插入图片描述
    reserve为字符串预留空间
    resize将有效字符串变成指定长度,多出的长度用指定字符补上

    void reserve (size_t n = 0);
    void resize (size_t n);
    void resize (size_t n, char c);

    #include 
    #include 
    using namespace std;
    int main()
    {
    	string s;
    	s.reserve(1000);//内存对齐会多出一些空间,总大小至少是n
    	cout << s.capacity() << endl;
    	s.reserve(15);//VS编译器下15及以下才会缩容,前提是原来对象中字符串不能超过15个长度
    	cout << s.capacity() << endl;
    	string s1("qwert");
    	cout << s1 << endl;
    	int sz = s1.size();
    	s1.resize(4);//不到原本字符串长度就将后面的字符串覆盖
    	cout << s1 << endl;
    	s1 = "qwert";
    	s1.resize(4, 'x');//不到原本字符串长度就将后面的字符串覆盖
    	cout << s1 << endl;
    	s1 = "qwert";
    	s1.resize(8, 'x');//不足就用字符x补上
    	cout << s1 << endl;
    	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

    在这里插入图片描述

    对象的修改

    push_back在后面追加一个字符
    append在后面追加一个字符串
    operator+=在后面追加一个字符串或字符还有对象

    void push_back (char c);
    string& append (const char* s);
    string& operator+= (const string& str);
    string& operator+= (const char* s);
    string& operator+= (char c);

    #include 
    #include 
    using namespace std;
    int main()
    {
    	string s("qwe");
    	string s1("123");
    	s += 'r';
    	cout << s << endl;
    	s += "ty";
    	cout << s << endl;
    	s += s1;
    	cout << s << endl;
    	string s2("zxc");
    	s2.push_back('v');
    	cout << s2 << endl;
    	s2.append("cpp");
    	cout << s2 << endl;
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在这里插入图片描述
    insert在指定位置插入指定内容(不推荐,时间复杂度高)
    pop_back尾删
    erase从指定位置删除指定长度的字符(不推荐,时间复杂度高)
    c_str返回C语言的字符串

    string& insert (size_t pos, const string& str);
    string& insert (size_t pos, const char* s);
    void pop_back();
    string& erase (size_t pos = 0, size_t len = npos);
    const char* c_str() const;

    #include 
    #include 
    using namespace std;
    int main()
    {
    	string s("qwert");
    	string s1("zxc");
    	s.insert(1, "ccc");
    	cout << s << endl;
    	s.insert(0, s1);
    	cout << s << endl;
    	s.pop_back();
    	cout << s << endl;
    	s.erase(2, 4);
    	cout << s << endl;
    	cout << s.c_str() << endl;//这里是为了方便做返回值
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    在这里插入图片描述
    find + npos从指定位置向后查找指定位置的字符(npos是string类中特殊的静态常量-1)
    rfind从指定位置向前查找指定位置的字符
    substr从指定位置截取n个字符返回

    size_t find (const string& str, size_t pos = 0) const;
    size_t find (const char* s, size_t pos = 0) const;
    size_t rfind (const string& str, size_t pos = npos) const;
    size_t rfind (const char* s, size_t pos = npos) const;
    string substr (size_t pos = 0, size_t len = npos) const;

    #include 
    #include 
    using namespace std;
    int main()
    {
    	string s("test.cpp");
    	int num = s.find("st", 0);
    	cout << num << endl;
    	num = s.find("st", 5);
    	cout << num << endl;
    	num = s.rfind("cpp", 7);
    	cout << num << endl;
    	num = s.rfind("cpp", 4);
    	cout << num << endl;
    	string s1 = s.substr(0, 4);
    	cout << s1 << endl;
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在这里插入图片描述

    访问及遍历操作

    operator[]返回对象下标的元素
    begin+ end迭代器,begin是字符串最开始的元素,end是字符串末尾的‘\0’
    rbegin + rend反向迭代器

    char& operator[] (size_t pos);
    const char& operator[] (size_t pos) const;
    iterator begin();
    const_iterator begin() const;
    iterator end();
    const_iterator end() const;
    reverse_iterator rbegin();
    const_reverse_iterator rbegin() const;
    reverse_iterator rend();
    const_reverse_iterator rend() const;

    #include 
    #include 
    using namespace std;
    int main()
    {
    	string s("qwert");
    	cout << s[2] << endl;
    	s = "123456";
    	string::iterator left1 = s.begin();//可读可写
    	string::const_iterator left2 = s.begin();//可读不可写
    	while (left1 != s.end())
    	{
    		*left1 += 1;
    		cout << *left1;
    		left1++;
    	}
    	cout << endl;
    	while (left2 != s.end())
    	{
    		cout << *left2;
    		left2++;
    	}
    	cout << endl;
    	string::reverse_iterator left3 = s.rbegin();
    	string::const_reverse_iterator left4 = s.rbegin();
    	while (left3 != s.rend())
    	{
    		*left3 += 1;
    		cout << *left3;
    		left3++;
    	}
    	cout << endl;
    	while (left4 != s.rend())
    	{
    		cout << *left4;
    		left4++;
    	}
    	cout << endl;
    	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

    C++11语法中的for循环就是与迭代器有关。
    在这里插入图片描述
    这里还有一个类似于operator[]的接口是at,找到的就返回,找不到会抛异常。
    在这里插入图片描述

    string中的swap与C++库中的swap的区别

    string::swap

    void swap (string& x, string& y);
    交换两个同类对象中的成员

    #include 
    #include 
    using namespace std;
    int main()
    {
    	string s1("asdq7777777777777777777");
    	string s2("qwe");
    	s1.swap(s2);
    	cout << s1 << endl;
    	cout << s1.size() << endl;
    	cout << s1.capacity() << endl;
    	cout << s2 << endl;
    	cout << s2.size() << endl;
    	cout << s2.capacity() << endl;
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在这里插入图片描述
    C++库swap
    这是一个模板

    template <class T> void swap ( T& a, T& b )
    {
      T c(a); a=b; b=c;//这里其实就相当于调用了构造函数,因为T会有自定义类型
    }
    
    • 1
    • 2
    • 3
    • 4

    平时我们的内置类型都是不需要进行析构和构造的,但是内置类型进入模板之后就需要了。
    使用时要注意深浅拷贝问题,自定义类型要调用 = 。

    非成员函数

    operator>>
    operator<<流插入流提取

    istream& operator>> (istream& is, string& str);
    ostream& operator<< (ostream& os, const string& str);

    这个就很熟悉了上面不知道用了多少。

    string类的模拟实现

    #include 
    #include 
    using namespace std;
    namespace baiye
    {
    	class string
    	{
    	public:
    		typedef char* iterator;
    		string(const char* s = "")//对象初始化,缺省值有一个隐藏的\0
    		{
    			_arr = new char[strlen(s) + 1];
    			strcpy(_arr, s);
    			_size = strlen(_arr);
    			_capacity = _size;//实际可以储存的大小,不算\0的位置
    		}
    		~string()//析构
    		{
    			delete[] _arr;
    			_arr = nullptr;
    			_size = 0;
    			_capacity = 0;
    		}
    		string(const string& s)//拷贝构造
    			:_arr(nullptr)
    			,_size(0)
    			,_capacity(0)
    		{
    			string tmp(s._arr);
    			swap(tmp);
    		}
    		string& operator=(string s)//这里不用引用就是临时变量,我们可以让它成为打工人
    		{
    			swap(s);
    			return *this;
    		}
    		//iterator
    		iterator begin()const
    		{
    			return _arr;
    		}
    		iterator end()const
    		{
    			return _arr + _size - 1;
     		}
    		// modify
    		const char* c_str()const
    		{
    			return _arr;
    		}
    		void push_back(char c)
    		{
    			if (_size == _capacity)
    			{
    				size_t len = _size == 0 ? 4 : _capacity * 2;//防止空对象扩容失败
    				reserve(len);
    			}
    			_arr[_size] = c;
    			_size++;//注意\0
    			_arr[_size] = '\0';
    		}
    		void append(const char* str)
    		{
    			if (_size + strlen(str) > _capacity)
    			{
    				reserve(_size + strlen(str) + 1);//不能二倍扩容,万一新加的字符串更大就不行了
    			}
    			strcpy(_arr + _size, str);
    			_size = strlen(_arr);
    		}
    		string& operator+=(char c)
    		{
    			push_back(c);
    			return *this;
    		}
    		string& operator+=(const char* str)
    		{
    			append(str);
    			return *this;
    		}
    		void clear()
    		{
    			_arr[0] = '\0';
    			_size = 0;
    		}
    		void swap(string& s)
    		{
    			std::swap(_arr, s._arr);
    			std::swap(_size, s._size);
    			std::swap(_capacity, s._capacity);
    		}
    		//capacity
    		size_t size()const//返回长度
    		{
    			return _size;
    		}
    		size_t capacity()const//返回容量
    		{
    			return _capacity;
    		}
    		bool empty()const
    		{
    			return _size;
    		}
    		void resize(size_t n, char c = '\0')
    		{
    			if (n <= _size)
    			{
    				_arr[n] = '\0';
    				_size = n;
    			}
    			else
    			{
    				reserve(n);
    				while (_size < n)
    				{
    					_arr[_size] = c;
    					_size++;
    				}
    				_arr[n] = '\0';
    				_size = n;
    			}
    		}
    		void reserve(size_t n)
    		{
    			char* tmp = new char[n + 1];//+1是为了算\0
    			strcpy(tmp, _arr);
    			delete[] _arr;
    			_arr = tmp;
    			_capacity = n;
    		}
    		// access
    		char& operator[](size_t x)//可读可写
    		{
    			assert(x < _size);
    			return _arr[x];
    		}
    		const char& operator[](size_t x)const//可读不可写
    		{
    			assert(x < _size);
    			return _arr[x];
    		}
    		//relational operators
    		int judge(const string& s)
    		{
    			return strcmp(_arr, s._arr);//1大于,0等于,-1小于
    		}
    		bool operator<(const string& s)
    		{
    			int a = judge(s);
    			if (a < 0)
    				return 1;
    			return 0;
    		}
    		bool operator<=(const string& s)
    		{
    			int a = judge(s);
    			if (a > 0)
    				return 0;
    			return 1;
    		}
    		bool operator>(const string& s)
    		{
    			int a = judge(s);
    			if (a > 0)
    				return 1;
    			return 0;
    		}
    		bool operator>=(const string& s)
    		{
    			int a = judge(s);
    			if (a < 0)
    				return 0;
    			return 1;
    		}
    		bool operator==(const string& s)
    		{
    			return !judge(s);
    		}
    		bool operator!=(const string& s)
    		{
    			return judge(s);
    		}
    		// 返回c在string中第一次出现的位置
    		size_t find(char c, size_t pos = 0) const
    		{
    			assert(pos < _size);
    			while (pos < _size)
    			{
    				if (_arr[pos] == c)
    					return pos;
    				pos++;
    			}
    			return npos;
    		}
    		// 返回子串s在string中第一次出现的位置
    		size_t find(const char* s, size_t pos = 0) const
    		{
    			assert(pos < _size);
    			const char * p =strstr(_arr + pos, s);
    			if (p == nullptr)
    			{
    				return npos;
    			}
    			else
    			{
    				return p - _arr;
    			}
    		}
    		// 在pos位置上插入字符c/字符串str,并返回该字符的位置
    		string& insert(size_t pos, char c)
    		{
    			if (_size == _capacity)
    			{
    				size_t len = _size == 0 ? 4 : _capacity * 2;//防止空对象扩容失败
    				reserve(len);
    			}
    			int end = _size + 1;
    			while (end > pos)
    			{
    				_arr[end] = _arr[end - 1];
    				end--;
    			}
    			_arr[pos] = c;
    			_size++;
    			return *this;
    		}
    		string& insert(size_t pos, const char* str)
    		{
    			int len = strlen(str);
    			if (_size + len > _capacity)
    			{
    				reserve(_size + len + 1);//不能二倍扩容,万一新加的字符串更大就不行了
    			}
    			int end1 = _size + 1;
    			int end2 = _size + len;
    			while (end1 > pos)
    			{
    				_arr[end2] = _arr[end1 - 1];
    				end1--;
    				end2--;
    			}
    			strncpy(_arr + pos, str, len);
    			_size = strlen(_arr);
    			return *this;
    		}
    		// 删除pos位置上的元素,并返回该元素
    		string& erase(size_t pos, size_t len = npos)//nops是默认值
    		{
    			if (len == npos || pos + len >= _size)//删除pos后面所有的数据
    			{
    				_arr[pos] = '\0';
    				_size = pos;
    			}
    			else
    			{
    				strcpy(_arr + pos, _arr + pos + len);
    				_size -= len;
    			}
    			return *this;
    		}
    	private:
    		char* _arr;//字符串储存的地方
    		int _size;//大小
    		int _capacity;//容量
    		const static size_t npos = -1;//C++只允许整形的静态成员在类的内部进行初始化
    	};
    	ostream& operator<<(ostream& out, const string& s)//不一定非要是友元
    	{
    		for (int i = 0; i < s.size(); i++)
    		{
    			out << s[i];
    		}
    		return  out;
    	}
    	istream& operator >> (istream& in, string& s)
    	{
    		s.clear();//清空原来s中的内容
    		char buff[128] = { '\0' };//创建一个容纳输入数据的数组
    		char c = in.get();
    		int i = 0;
    		while (c != '\n')
    		{
    			if (i == 127)
    			{
    				i = 0;
    				s += buff;//数组满了放入s中,防止s不断扩容
    			}
    			buff[i++] = c;
    			c = in.get();
    		}
    		if (i > 0)
    		{
    			buff[i] = '\0';
    			s += buff;
    		}
    		return in;
    	}
    }
    
    • 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
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299

    深浅拷贝与现代写法

    这里最重要的是深浅拷贝的现代写法,之前说过类的默认拷贝函数只能实现浅拷贝无法实现深拷贝,需要自定义拷贝函数,类与对象二
    现代写法是让一个新创建的对象帮你拷贝,然后与你进行交换,相当于你有了一个打工人。

    string(const string& s)//拷贝构造
    	:_arr(nullptr)//将被拷贝的对象进行初始化
    	,_size(0)
    	,_capacity(0)
    {
    	string tmp(s._arr);//打工人tmp
    	swap(tmp);//这里虽然只传参了一个tmp,但是还有一个隐藏的this指针
    }
    string& operator=(string s)//这里不用引用就是临时变量,我们可以让它成为打工人
    {
    	swap(s);
    	return *this;
    }
    void swap(string& s)
    {
    	std::swap(_arr, s._arr);
    	std::swap(_size, s._size);
    	std::swap(_capacity, s._capacity);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在这里插入图片描述
    之后tmp的成员 _arr指向的就是空指针,进行析构也不会报错,其他成员全都变成0,而需要被拷贝的*this就成功的得到了想要的数据。

  • 相关阅读:
    kubernetes之kubectl与YAML详解1
    无重复字符的最长子串(python3)
    第八节:类和对象【二】【this引用和包】
    正则表达式概念
    后台运行python程序并查看运行的python 进程
    MQ消费堆积问题解决思路
    图像文件格式大全及代码检测方式
    家具行业APS解决方案
    再探格林公式、斯托克斯公式、高斯公式
    uni-app--》基于小程序开发的电商平台项目实战(六)
  • 原文地址:https://blog.csdn.net/qq_63580639/article/details/127470477