C++ stl容器string的底层模拟实现

这篇具有很好参考价值的文章主要介绍了C++ stl容器string的底层模拟实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

C++ stl容器string的底层模拟实现,C++,c++,开发语言

目录

前言:

1.成员变量

2.构造函数与拷贝构造函数

3.析构函数

4.赋值重载

5.[]重载

6.比较关系重载

7.reserve

8.resize

9.push_back,append和重载+=

10.insert

11.erase

12.find

14.迭代器

15.流插入,流提取重载

16.swap

17.c_str

18.完整代码+测试

总结:


前言: 本篇模拟string类的底层实现,只会调一些重要的接口实现,结尾附上完整代码。

1.成员变量

	private:
		//const char* _str
		//不使用const修饰,string类的字符串是可以修改的,而且例如扩容的时候也需要修改指针的指向
		// 然后就是_str的初始化是最好new出来的,如果直接初始化为空指针,例如在流插入的时候需要解引用,就不行了。		
		char* _str;
		size_t _capacity;
		size_t _size;

		//static const size_t npos=-1;//静态成员变量要在类外声明初始化,不能给缺省值,但是如果加上const,又支持这样给缺省值的语法了
		static const size_t npos;

首先注意的就是_str,不能是const类型的,因为我们的string字符串是可以改的,而且如果是const类型的,在扩容等也需要改变指针的指向;而且我们在流插入的时候解引用,所以在初始化的时候最好是new出来的。

静态成员常量npos需要在类外声明初始化,注意的是,本来静态成员变量是不能给缺省值的,但是加上了const就又可以给缺省值了。

2.构造函数与拷贝构造函数

		string(const char* str="")//strlen遇到字符0就停了,这样传参数也正好,无参的size也是0,或者写成"\0",但是不能写成'\0'类型不匹配
			:_size(strlen(str))//strlen内部获取字符串长度是需要解引用的,所以最好初始化不要给空指针,
		{
			_capacity = _size == 0 ? 3 : _size;
			_str = new char[_capacity + 1];//+1给字符0准备,实际capacity没有字符0
			strcpy(_str, str);
		}

	    string(const string& st)
			:_size(st._size)
			,_capacity(st._capacity)
		{
			_str = new char[st._capacity + 1];//+1给字符0准备,实际capacity没有字符0
			strcpy(_str, st._str);
		}

构造的参数这样写是因为这样传参数相当于无参的构造只有一个字符0,正好符合strlen计算长度的规则,无参的时候_size就是0了。

_capacity需要判断是否为0,不然什么都没有直接二倍扩容会出错。

_str的容量加1是给字符0准备的,但是实际_size与_capacity是没有计算字符0的,而且在调试的时候也看不到,但是还是要加上。

构造的思路就是根据传参字符串的的容量开一块新的空间,进行拷贝完成初始化。

拷贝构造就是深拷贝了,所以就是根据要拷贝的对象的大小开一块空间,再让空间拷贝给给调用的对象,注意容量与大小也要变。

3.析构函数

		~string()
		{
			delete[] _str;
			_str = nullptr;
			_size = 0;
			_capacity = 0;
		}

注意配套使用delete就行。

4.赋值重载

		string& operator=(const string& st)
		{
			//这样写如果new出错了,原来的对象也被破坏了
			//delete[] _str;
			//_str = new char[st._capacity + 1];
			//strcpy(_str, st._str);
			//_capacity = st._capacity;
			//_size = st._size;


			if (this != &st)
			{
				char* tmp = new char[st._capacity + 1];
				strcpy(tmp,st._str);
				delete[] _str;
				_str = tmp;

				_capacity = st._capacity;
				_size = st._size;

				return *this;
			}
		}

赋值重载就要考虑空间的问题了,同时也是一个深拷贝。

假设s1=s2,如果s1容量多,直接将s2赋值过去没问题,但是会造成空间的浪费。

如果s1的空间少,此时再将s2赋值就会出现问题了,所以综合一下:先让原空间也就是被赋值的空间给释放掉,然后再根据赋值的内容开辟空间,让被赋值的指向这块新的空间,再进行拷贝,并完成大小和容量的更新。

上面的为注释的写法,但是还有一点问题,如果new失败了,那被赋值的空间早已被释放了,这就破坏了原来的空间,所以为了不破坏原有的空间,先根据赋值的内容开一块空间,再将赋值的内容拷贝给这块空间,此时再释放旧空间,再将旧空间指向新空间即可。

注意要判断自己不能给自己赋值。

5.[]重载

		const char& operator[](size_t pos) const
		{
			assert(pos < _size);
			return _str[pos];
		}

		char& operator[](size_t pos) 
		{
			assert(pos < _size);
			return _str[pos];
		}

注意断言,下标位置不能等于_size,_size指向最后一个字符的下一个也就是字符0,但是实际库中的string的字符0我们是可以访问到的,这里主要表示有效数据的访问。

要提供两个版本,方便const对象调用。 

6.比较关系重载

		 //string比较
		 bool operator>(const string& st) const
		 {
			 return strcmp(_str, st._str) > 0;
		 }

		 bool operator==(const string& st) const
		 {
			 return strcmp(_str, st._str) == 0;
		 }
		 
		 bool operator>=(const string& st) const
		 {
			 return *this > st || *this == st;//如果不用const修饰==的重载,这里调用就不能st==*this了,因为st是const类型的		 
		 }

		 bool operator<(const string& st) const
		 {
			 return !(*this >= st);
		 }

		 bool operator<=(const string& st) const
		 {
			 return !(*this > st);
		 }

		 bool operator!=(const string& st) const
		 {
			 return !(*this == st);
		 }

这个没什么好说的了,就是写两个复用就完了。

注意没有修改成员变量的成员函数最好还是就是const,像>=复用==的逻辑的时候,如果==不是const的成员函数,就不能倒过来写了。 

7.reserve

		 void reserve(size_t n)
		 {
			 if (n > _capacity)//如果n小于这块空间,相当于缩容了,原字符串再拷贝给缩容的空间就越界了
			 {
				 char* tmp = new char[n + 1];//这里一样是放在原对象被破坏,+1用来存放字符0
				 strcpy(tmp, _str);
				 delete[] _str;
				 _str = tmp;

				 _capacity = n;//但是capacity实际还是没有字符0的
			 }

注意判断扩容的大小不能小于原有的容量,不然就是缩容了,缩容再拷贝数据就越界了。

8.resize

		 void resize(size_t n, char ch = '\0')
		 {
			 if (n <= _capacity)
			 {
				 //保留前n个数据
				 _size = n;
				 _str[_size] = '\0';
			 }
			 else
			 {
				 if (n > _capacity)
				 {
					 reserve(n);
				 }

				 size_t i = _size;//直接在后面补初始化的数据
				 while (i < n)
				 {
					 _str[i] = ch;
					 ++i;
				 }

				 _size = n;
				 _str[_size] = '\0';
			 }
		 }

如果扩容大小小于容量,那就保留前n个数据,末尾改成字符0。

如果大,那就扩容,原有数据不变,扩容后面的数据都默认初始化为字符0。如果传的有参数,就往末尾补数据,最后别忘了更新size,还要在最后补字符0。

9.push_back,append和重载+=

		 void push_back(char ch)
		 {
			 if (_size + 1 > _capacity)
			 {
				 reserve(_capacity * 2);
			 }

			 _str[_size] = ch;
			 ++_size;
			 _str[_size] = '\0';//插入完了,字符串后面的字符0就找不到了,所以size更新完后再补一个字符0

			 //复用insert
			 //insert(_size,ch)
		 }

		 void append(const char* str)
		 {
			 size_t len = strlen(str);
			 if (_size + len > _capacity)
			 {
				 reserve(_size + len);
			 }

			 strcpy(_str + _size, str);//正好覆盖了原字符串的字符0
			 _size += len;

			 //复用insert
			 //insert(_size,str)
		 }
		 string& operator+=(char ch)
		 {
			 push_back(ch);
			 return *this;
		 }

		 string& operator+=(const char* str)
		 {
			 append(str);
			 return *this;
		 }

注意尾插一个字符时的字符0的补充以及扩容即可。 

10.insert

		 string& insert(size_t pos, char ch)
		 {
			 assert(pos <= _size);
			 if (_size + 1 > _capacity)
			 {
				 reserve(_capacity * 2);
			 }
			 size_t end = _size + 1;

			 while (end > pos)
			 {
				 _str[end] = _str[end - 1];
				 --end;
			 }

			 _str[pos] = ch;
			 ++_size;

			 return *this;
		 }

		 string& insert(size_t pos, const char* str)
		 {
			 assert(pos <= _size);
			 size_t len = strlen(str);
			 if (_size + len > _capacity)
			 {
				 reserve(_size + len);
			 }

			 size_t end = _size + len;
			 while (end >pos+len-1)
			 {
				 _str[end] = _str[end - len];
				 --end;
			 }
			 strncpy(_str + pos, str, len);
			 _size += len;
			 return *this;

		 }

这个建议画图理解,也一样先扩容。

注意断言,在等于size的时候插入就是尾插入,不用添加字符0,直接交换了,注意pos是下标。 

11.erase

		 string& erase(size_t pos, size_t len = npos)//删除pos位置(包括pos位置)后的len个字符,如果不够删,就删完
		 {
			 assert(pos < _size);
			 if (len == npos || pos + len >= _size)
			 {
				 _str[pos] = '\0';//pos也被删了
				 _size = pos;
			 }
			 else
			 {
				 strcpy(_str + pos, _str + pos + len);
				 _size -= len;
			 }

			 return *this;
		 }

当等于缺省值的时候或者要删的字符正好删到了最后一个有效数据,直接就是在pos的位置放字符0,更新size就行了(注意pos位置的值也被删了)。

如果没有删完,就将删除后右边的子串与原字符串连接起来,更新size。 

12.find

		 size_t find(char ch, size_t pos=0)//pos为0就是代表找这个字符出现的第一个位置,返回下标;为1就是返回出现第二次的位置的下标
		 {
			 assert(pos < _size);
			 for (size_t i = pos; i < _size; ++i)
			 {
				 if (_str[i] == ch)
				 {
					 return i;
				 }
			 }

			 return npos;
		 }

		 size_t find(const char* str, size_t pos = 0)
		 {
			 char* p = strstr(_str + pos, str);//找子串可以使用暴力的kmp,但是实际作用不大,还有BM算法;strstr使用的是暴力的算法
			 if (p == nullptr)
			 {
				 return npos;
			 }
			 else
			 {
				 return p - _str;
			 }
		 }

 查找字符就是遍历一遍就行了,查找字符串需要使用strstr或者算法,也就是查找子串,strstr返回的是子串的首元素位置。

14.迭代器

		typedef char* iterator;
		typedef const char* const_iterator;

		iterator begin()
		{
			return _str;
		}

		iterator end()
		{
			return _str + _size;
		}

		const_iterator begin() const
		{
			return _str;
		}

		const_iterator end() const
		{
			return _str + _size;
		}

对指针的重命名,后面容器的实现更复杂,后面再说。

注意还有const迭代器,供const对象调用,这里分开划分const成员与非const成员函数主要是因为我们使用普通迭代器大部分会修改数据。 

15.流插入,流提取重载

	ostream& operator<<(ostream& out, const string& s)
	{
		for (auto ch : s)
		{
			out << ch;//有些编译器会让字符0打印成空格
		}

		return out;
	}

	istream& operator>>(istream& in, string& s)
	{
		s.clear();
		char ch = in.get();
		char buff[128];
		size_t i = 0;
		while (ch != ' ' && ch != '\n')
		{
			buff[i++] = ch;
			if (i == 127)
			{
				buff[127] = '\0';
				s += buff;
				i = 0;
			}

			ch = in.get();
		}

		if (i != 0)//防止后面还有数据没填
		{
			buff[i] = '\0';
			s += buff;
		}

		return in;
	}

注意不是友元,没有访问类的成员。 

16.swap

		 void swap(string& st)
		 {
			 std::swap(_str, st._str);
			 std::swap(_size, st._size);
			 std::swap(_capacity, st._capacity);
		 }

直接复用即可,如果直接写调用要写成s1.swap(s2),会有两个对象三个深拷贝。 

17.c_str

		const char* c_str()
		{
			return _str;
		}

直接返回首字符地址,注意是const类型的。 文章来源地址https://www.toymoban.com/news/detail-856522.html

18.完整代码+测试

#pragma once
#include <string>
#include <string.h>
#include <assert.h>
#include <iostream>

using namespace std;

namespace my_string
{
	class string
	{
	public:
		typedef char* iterator;
		typedef const char* const_iterator;

		iterator begin()
		{
			return _str;
		}

		iterator end()
		{
			return _str + _size;
		}

		const_iterator begin() const
		{
			return _str;
		}

		const_iterator end() const
		{
			return _str + _size;
		}

		string(const char* str="")//strlen遇到字符0就停了,这样传参数也正好,无参的size也是0,或者写成"\0",但是不能写成'\0'类型不匹配
			:_size(strlen(str))//strlen内部获取字符串长度是需要解引用的,所以最好初始化不要给空指针,
		{
			_capacity = _size == 0 ? 3 : _size;
			_str = new char[_capacity + 1];//+1给字符0准备,实际capacity没有字符0
			strcpy(_str, str);
		}

	    string(const string& st)
			:_size(st._size)
			,_capacity(st._capacity)
		{
			_str = new char[st._capacity + 1];//+1给字符0准备,实际capacity没有字符0
			strcpy(_str, st._str);
		}

		string& operator=(const string& st)
		{
			//这样写如果new出错了,原来的对象也被破坏了
			//delete[] _str;
			//_str = new char[st._capacity + 1];
			//strcpy(_str, st._str);
			//_capacity = st._capacity;
			//_size = st._size;


			if (this != &st)
			{
				char* tmp = new char[st._capacity + 1];
				strcpy(tmp,st._str);
				delete[] _str;
				_str = tmp;

				_capacity = st._capacity;
				_size = st._size;

				return *this;
			}
		}

		~string()
		{
			delete[] _str;
			_str = nullptr;
			_size = 0;
			_capacity = 0;
		}

		const char* c_str()
		{
			return _str;
		}

		const char& operator[](size_t pos) const
		{
			assert(pos < _size);
			return _str[pos];
		}

		char& operator[](size_t pos) 
		{
			assert(pos < _size);
			return _str[pos];
		}

		 size_t size() const//size和capacity实际都没有算字符0,但是在string里面实际是有这个字符0的,但是调试是看不到的
		 {
			 return _size;
		 }

		 size_t capacity() const
		 {
			 return _capacity;
		 }

		 //string比较
		 bool operator>(const string& st) const
		 {
			 return strcmp(_str, st._str) > 0;
		 }

		 bool operator==(const string& st) const
		 {
			 return strcmp(_str, st._str) == 0;
		 }
		 
		 bool operator>=(const string& st) const
		 {
			 return *this > st || *this == st;//如果不用const修饰==的重载,这里调用就不能st==*this了,因为st是const类型的		 
		 }

		 bool operator<(const string& st) const
		 {
			 return !(*this >= st);
		 }

		 bool operator<=(const string& st) const
		 {
			 return !(*this > st);
		 }

		 bool operator!=(const string& st) const
		 {
			 return !(*this == st);
		 }

		 void reserve(size_t n)
		 {
			 if (n > _capacity)//如果n小于这块空间,相当于缩容了,原字符串再拷贝给缩容的空间就越界了
			 {
				 char* tmp = new char[n + 1];//这里一样是放在原对象被破坏,+1用来存放字符0
				 strcpy(tmp, _str);
				 delete[] _str;
				 _str = tmp;

				 _capacity = n;//但是capacity实际还是没有字符0的
			 }
		 }

		 void push_back(char ch)
		 {
			 if (_size + 1 > _capacity)
			 {
				 reserve(_capacity * 2);
			 }

			 _str[_size] = ch;
			 ++_size;
			 _str[_size] = '\0';//插入完了,字符串后面的字符0就找不到了,所以size更新完后再补一个字符0

			 //复用insert
			 //insert(_size,ch)
		 }

		 void append(const char* str)
		 {
			 size_t len = strlen(str);
			 if (_size + len > _capacity)
			 {
				 reserve(_size + len);
			 }

			 strcpy(_str + _size, str);//正好覆盖了原字符串的字符0
			 _size += len;

			 //复用insert
			 //insert(_size,str)
		 }

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

		 string& operator+=(const char* str)
		 {
			 append(str);
			 return *this;
		 }

		 void resize(size_t n, char ch = '\0')
		 {
			 if (n <= _capacity)
			 {
				 //保留前n个数据
				 _size = n;
				 _str[_size] = '\0';
			 }
			 else
			 {
				 if (n > _capacity)
				 {
					 reserve(n);
				 }

				 size_t i = _size;//直接在后面补初始化的数据
				 while (i < n)
				 {
					 _str[i] = ch;
					 ++i;
				 }

				 _size = n;
				 _str[_size] = '\0';
			 }
		 }

		 string& insert(size_t pos, char ch)
		 {
			 assert(pos <= _size);
			 if (_size + 1 > _capacity)
			 {
				 reserve(_capacity * 2);
			 }
			 size_t end = _size + 1;

			 while (end > pos)
			 {
				 _str[end] = _str[end - 1];
				 --end;
			 }

			 _str[pos] = ch;
			 ++_size;

			 return *this;
		 }

		 string& insert(size_t pos, const char* str)
		 {
			 assert(pos <= _size);
			 size_t len = strlen(str);
			 if (_size + len > _capacity)
			 {
				 reserve(_size + len);
			 }

			 size_t end = _size + len;
			 while (end >pos+len-1)
			 {
				 _str[end] = _str[end - len];
				 --end;
			 }
			 strncpy(_str + pos, str, len);
			 _size += len;
			 return *this;

		 }

		 string& erase(size_t pos, size_t len = npos)//删除pos位置(包括pos位置)后的len个字符,如果不够删,就删完
		 {
			 assert(pos < _size);
			 if (len == npos || pos + len >= _size)
			 {
				 _str[pos] = '\0';//pos也被删了
				 _size = pos;
			 }
			 else
			 {
				 strcpy(_str + pos, _str + pos + len);
				 _size -= len;
			 }

			 return *this;
		 }

		 void swap(string& st)
		 {
			 std::swap(_str, st._str);
			 std::swap(_size, st._size);
			 std::swap(_capacity, st._capacity);
		 }

		 size_t find(char ch, size_t pos=0)//pos为0就是代表找这个字符出现的第一个位置,返回下标;为1就是返回出现第二次的位置的下标
		 {
			 assert(pos < _size);
			 for (size_t i = pos; i < _size; ++i)
			 {
				 if (_str[i] == ch)
				 {
					 return i;
				 }
			 }

			 return npos;
		 }

		 size_t find(const char* str, size_t pos = 0)
		 {
			 char* p = strstr(_str + pos, str);//找子串可以使用暴力的kmp,但是实际作用不大,还有BM算法;strstr使用的是暴力的算法
			 if (p == nullptr)
			 {
				 return npos;
			 }
			 else
			 {
				 return p - _str;
			 }
		 }
		 
		 void clear()
		 {
			 _str[0] = '\0';
			 _size = 0;
		 }
	private:
		//const char* _str
		//不使用const修饰,string类的字符串是可以修改的,而且例如扩容的时候也需要修改指针的指向
		// 然后就是_str的初始化是最好new出来的,如果直接初始化为空指针,例如在流插入的时候需要解引用,就不行了。		
		char* _str;
		size_t _capacity;
		size_t _size;

		//static const size_t npos=-1;//静态成员变量要在类外声明初始化,不能给缺省值,但是如果加上const,又支持这样给缺省值的语法了
		static const size_t npos;

	};

	const size_t string::npos = -1;

	ostream& operator<<(ostream& out, const string& s)
	{
		for (auto ch : s)
		{
			out << ch;//有些编译器会让字符0打印成空格
		}

		return out;
	}

	istream& operator>>(istream& in, string& s)
	{
		s.clear();
		char ch = in.get();
		char buff[128];
		size_t i = 0;
		while (ch != ' ' && ch != '\n')
		{
			buff[i++] = ch;
			if (i == 127)
			{
				buff[127] = '\0';
				s += buff;
				i = 0;
			}

			ch = in.get();
		}

		if (i != 0)//防止后面还有数据没填
		{
			buff[i] = '\0';
			s += buff;
		}

		return in;
	}

	void test_string1()
	{
		string s1;
		string s2("hello world");

		cout << s1.c_str() << endl;
		cout << s2.c_str() << endl;

		s2[0]++;
		cout << s2.c_str() << endl;
	}

	void test_string2()
	{
		string s1;
		string s2("hello world");
		string s3(s2);//经典的浅拷贝问题
		//对于自定义类型,去调用默认的拷贝构造,但由于空间是new出来的,所以s2和s3指向的空间是一样的
		//会造成两个问题:两次析构和修改的时候互相影响
		//如何深拷贝?先拷贝下来一块空间,再让值拷贝下来,再让被拷贝的对象指向这块空间
		cout << s1.c_str() << endl;
		cout << s2.c_str() << endl;
		cout << s3.c_str() << endl;

		s1 = s3;//赋值和拷贝构造类似,默认生成的也是浅拷贝
		cout << s1.c_str() << endl;
		cout << s3.c_str() << endl;
	}

	void Print(const string& s)//传值传参会调拷贝构造,也要深拷贝;const对象,调用的函数也要是const
	{
		for (size_t i = 0; i < s.size(); ++i)
		{
			cout << s[i] << " ";
		}
		cout << endl;


		string::const_iterator it = s.begin();//再使用范围for就OK了
		while (it != s.end())
		{
			//cout << (*it)-- << " ";只能读,不能写
			++it;
		}
		cout << endl;

		/*for (auto ch : s)//这里就用不了了,因为范围for是替换的迭代器,这里用迭代器也不行,这里是const对象,而普通的迭代器会修改内容,权限被放大了
		{
			cout << ch << " ";
		}
		cout << endl;*/

	}

	void test_string3()
	{
		string s1("hello world");
		for (size_t i = 0; i < s1.size(); ++i)
		{
			s1[i]++;
		}
		cout << endl;
		Print(s1);

		string::iterator it = s1.begin();
		while (it != s1.end())
		{
			cout << (*it)-- << " ";
			++it;
		}
		cout << endl;

		it = s1.begin();
		while (it != s1.end())
		{
			cout << *it << " ";
			++it;
		}
		cout << endl;

		for (auto ch : s1)//实现了迭代器就能用范围for,因为它的底层就是宏,替换的迭代器,迭代器begin改成Begin就不能用范围for了
		{
			cout << ch << " ";
		}
		cout << endl;
	}

	void test_string4()
	{
		string s1("hello world");
		string s2("hello world");
		string s3("xx");

		cout << (s1 < s2) << endl;//比较ascii码
		cout << (s1 == s2) << endl;
		cout << (s1 >= s2) << endl;
	}

	void test_string5()
	{
		string s1("hello world");
		//s1.push_back(' ');
		//s1.append("xxxxxxxxxxxxxxxxxxxx");


		s1 += ' ';
		s1 += "xxxxxxxxxxxxxxxxx";
		cout << s1.c_str() << endl;

		s1.insert(5, 'x');
		cout << s1.c_str() << endl;
	}

	void test_string6()
	{
		string s1("hello world111111111111111111111111");
		cout << s1.capacity() << endl;
		s1.reserve(10);
		cout << s1.capacity() << endl;
	}

	void test_string7()
	{
		string s1;
		s1.resize(20, 'x');
		cout << s1.c_str() << endl;
		s1.resize(30, 'y');
		cout << s1.c_str() << endl;

		s1.resize(10);
		cout << s1.c_str() << endl;
	}

	void test_string8()
	{
		string s1("hello world");
		s1.insert(0, 'x');
		cout << s1.c_str() << endl;
		s1.insert(0, "yyy");
		cout << s1.c_str() << endl;

		s1.erase(5, 1);
		cout << s1.c_str() << endl;
		s1.erase(5, 30);
		cout << s1.c_str() << endl;

	}
	//流插入重载必须实现成友元函数?不对,没有访问类中的成员,不需要
	void test_string9()
	{
		string s1("hello world");
		s1 += '\0';
		s1 += "xxxxxxxxx";
		cout << s1 << endl;
		cout << s1.c_str() << endl;

		string s2;
		cin >> s2;
		cout << s2 << endl;
	}

}

总结:

细节很多,后面的容器实现大部分类似,但还需要复习。

到了这里,关于C++ stl容器string的底层模拟实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • [C++] STL_priority_queue(优先级队列) 的使用及底层的模拟实现,容器适配器,deque的原理介绍

    priority_queue文档介绍 翻译: 1. 优先队列是一种 容器适配器 ,根据严格的弱排序标准, 它的第一个元素总是它所包含的元素中最大的。 2. 此上下文类似于 堆 , 在堆中可以随时插入元素,并且只能检索最大堆元素(优先队列中位于顶部的元素)。 3. 优先队列被实现为容器适配

    2024年02月04日
    浏览(46)
  • C++ STL string类模拟实现

    目录 string类成员变量 一.构造函数 二.析构函数 三.拷贝构造 四.size(),capacity() 五.operator [ ] 六. operator =  七.字符串比较  八.reserve() 九.push_back(),append() 十.operator+=  十一.insert()  十二.迭代器  十二.erase() 十三.swap()  十四.find() 十五.流提取,流输出 十六

    2024年02月14日
    浏览(52)
  • C++ [STL之string模拟实现]

    本文已收录至《C++语言》专栏! 作者:ARMCSKGT 前面我们介绍了STL容器string的部分接口使用,有了string使我们对字符串的操作如鱼得水,其实string不止于使用方便,其实现也有许多我们值得学习的地方,本节将为您介绍string常用接口的代码实现! 本文接口的实现借助于C++官方

    2024年02月05日
    浏览(49)
  • 【C++】STL之string功能及模拟实现

    目录 前沿 一、标准库中的string类 二、string类的常用接口说明  1、string类对象的常见构造  2、string类对象的容量操作  3、string类对象的访问及遍历操作  4、string类对象的修改操作  5、string类非成员函数  6、vs下string结构的说明 三、string类的模拟实现  1、构造函数  2、析

    2024年02月15日
    浏览(45)
  • 【C++精华铺】10.STL string模拟实现

            STL(标准模板库)是一个C++标准库,其中包括一些通用的算法、容器和函数对象。STL的容器是C++ STL库的重要组成部分,它们提供了一种方便的方式来管理同类型的对象。其中,STLstring是一种常用的字符串类型。         STLstring是一个类,它封装了字符串的操作

    2024年02月09日
    浏览(49)
  • STL中的string类的模拟实现【C++】

    构造函数设置为缺省参数,若不传入参数,则默认构造为空字符串。字符串的初始大小和容量均设置为传入C字符串的长度(不包括’\\0’) 在模拟实现拷贝构造函数前,我们应该首先了解深浅拷贝: 浅拷贝:拷贝出来的目标对象的指针和源对象的指针指向的内存空间是同一

    2024年02月15日
    浏览(41)
  • C++ STL学习之【string的模拟实现】

    ✨个人主页: Yohifo 🎉所属专栏: C++修行之路 🎊每篇一句: 图片来源 The key is to keep company only with people who uplift you, whose presence calls forth your best. 关键是只与那些提升你的人在一起,他们的存在唤起了你最好的一面。 string 本质上就是一个专注于存储字符的顺序表,使用起来

    2023年04月09日
    浏览(70)
  • 【c++】:模拟实现STL模板中的string

        文章目录 前言 一.string的模拟实现 总结   上一篇文章我们详细介绍了STL中的string的一些常用的接口,这一篇文章我们将从底层实现string类,当然我们只是实现一些重要的,经常使用的接口,并且不是完全按照STL中的string去走的。   首先我们为了防止我们写的string类与库

    2024年01月20日
    浏览(55)
  • 【C++初阶】STL详解(二)string类的模拟实现

    本专栏内容为:C++学习专栏,分为初阶和进阶两部分。 通过本专栏的深入学习,你可以了解并掌握C++。 💓博主csdn个人主页:小小unicorn ⏩专栏分类:C++ 🚚代码仓库:小小unicorn的代码仓库🚚 🌹🌹🌹关注我带你学习编程知识 注:为了防止与标准库当中的string类产生命名冲

    2024年02月05日
    浏览(57)
  • 【C++】深度剖析string类的底层结构及其模拟实现

    在上两篇中,我们已经学习了string类的一个使用,并且做了一些相关的OJ练习,相信大家现在对于string的使用已经没什么问题了。 那我们这篇文章呢,就来带大家对string进行一个模拟实现,这篇文章过后,有些地方大家或许就可以理解的更深刻一点。 那通过之前文章的学习我

    2023年04月17日
    浏览(106)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包