c++初阶-----STL---string的模拟实现

作者前言

🎂 ✨✨✨✨✨✨🍧🍧🍧🍧🍧🍧🍧🎂
​🎂 作者介绍: 🎂🎂
🎂 🎉🎉🎉🎉🎉🎉🎉 🎂
🎂作者id:老秦包你会, 🎂
简单介绍:🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂
喜欢学习C语言、C++和python等编程语言,是一位爱分享的博主,有兴趣的小可爱可以来互讨 🎂🎂🎂🎂🎂🎂🎂🎂
🎂个人主页::小小页面🎂
🎂gitee页面:秦大大🎂
🎂🎂🎂🎂🎂🎂🎂🎂
🎂 一个爱分享的小博主 欢迎小可爱们前来借鉴🎂


成员

前面我们学习了string的大致知道了这个类里面有很多的类的成员函数
如果我们要模拟这个自定义类型,我们需要开辟一个命名空间

namespace bit
{
	class string
	{
		private:
		char* _str;
		size_t _size;//字符串的大小
		size_t _capacity;//初始化的时候永远比真正的字符串大小小于1
		const static size_t npos;//静态成员,不属于某个对象,属于全部对象共用
	}
	
}


成员函数

构造函数

在string中有很多种构造函数,我模拟其中的两种

		string(const char* str = "")
		{
			_size = strlen(str);
			_capacity = _size;
			_str = new char[_capacity+1];
			strcpy(_str, str);
		}
		string(const string& str)
		{
			_size=str._size;
			_str = new char[str._capacity + 1];
			strcpy(_str, str._str);
			_capacity = str._capacity;
		}

记住,我们一定要进行深拷贝否则的话,我们在赋值其他string的对象的时候,如果是浅拷贝,就会只拷贝值过去,就会共用一块地址,也有可以用到的地址是一个临时地址,

析构函数

这里我简单的模拟一下

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

其他函数

c_str

const char* c_str() const
		{
			return _str;
		}

这个函数是把自定义类型的字符串转变成内置类型的字符串

字符串长度

size_t size() const
	{
		return _size;
	}

size_t capacity() const
	{
		return _capacity;
	}

尾插

void push_back(char c)
		 {
			 if (_size == _capacity)
			 {
				 size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;
				 _capacity = newcapacity;
				 char* tmp = new char[newcapacity];
				 strcpy(tmp, _str);
				 delete[] _str;
				 _str = tmp;
			 }
			 _str[_size++] = c;
			 _str[_size] = '\0';

		 }

reserve

更改容量

 void reserve(size_t n)
		 {
			 if (n > _capacity)
			 {
				 char* tmp = new char[n+1];
				 strcpy(tmp, _str);
				 delete[] _str;
				 _str = tmp;
				 _capacity = n;

			 }
		 }

append

增加字符串

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

		 }

insert

指定位置插入字符串

		 string& insert(size_t pos, const char* str)
		 {
			 assert(pos <= _size);
			 size_t size = strlen(str);
			 if (size + _size > _capacity)
			 {
				 reserve(_size + size);
			 }
			 int idx = _size-1; 
			 _str[_capacity] = '\0';
			 while (idx>=(int)pos)
			 {
				 _str[idx + size] = _str[idx];
				 idx--;
			 }
			 strncpy(_str + pos, str, size);
			 _size += size;
			 return *this;

		 }

erase

删除字符串

void erase(size_t pos = 0, size_t len = npos)
	{
		if (pos + len >= _size - 1)
			 {
				 _str[pos] = '\0';
				 _size = pos;
			 }
			 else
			 {
				 strcpy(_str + pos, _str + pos + len);
				 _size -= len;
			 }
		 }

find

寻找字符串

		 size_t find(size_t pos, const char* str)
		 {
			 char* ptr = strstr(_str + pos, str);
			 if (ptr != nullptr)
				 return ptr - _str;
			 return -1;
		 }

substr

 string substr(size_t pos = 0, size_t len = npos)//这个函数,如果没有写深拷贝或者赋值的深拷贝,就会程序崩溃,
		 {
			 assert(pos < _size);
			 int end = pos + npos;
			 if (len == npos || pos + len >= _size)
			 {
				 end = _size;
			 }
			 string str;

			 str.reserve(end - pos);
			 int i = 0;
			 for (i = pos; i < end; i++)
			 {
				 push_back(_str[i]);
			 }
			 return str;
		 }

这里主要注意的是拷贝构造的时候,一定要深拷贝,或者的话返回的string的对象只是一个临时对象具有常性,需要用const进行接收,不能发生权限放大,销毁的只是这个对象的地址,而_str指向的那块地址有没有销毁,要看析构函数(不是临时对象销毁,而是在substr中定义的对象),

迭代器

前面我们知道string的迭代器,大概是一个指针
所以我们可以把char* 类型重定义为 iteraotr

typedef char* iterator;
iterator begin()
{
	return _str;
}

const iterator begin() const
{
	return _str;
}

iterator end()
{
	return _str + _size;
}

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

操作符重载

[]

这两个一个是给const类型的,一个是给没有const类型的

//可读
		 const char& operator[](size_t i) const
		{
			assert(i < _size);
			return _str[i];
		}
		 //可读可写
		 char& operator[](size_t i)
		 {
			 assert(i < _size);
			 return _str[i];
		 }

+和+=

		 string& operator=(const string& str)
		 {
			 _size = str._size;
			 _str = new char[str._capacity + 1];
			 strcpy(_str, str._str);
			 _capacity = str._capacity;
			 return *this;
		 }
		 string& operator+=(const char* str)
		 {
			 append(str);
			 return *this;
		 }
		 string& operator+=(char str)
		 {
			 push_back(str);
			 return *this;
		 }

<< 重载

前面的一篇文章,使用了友元函数,主要就是友元函数可以访问 类的私有成员,
这里我们不使用友元,直接在类外面进行重载

ostream& operator<<(ostream& on, string& str)
	{
		for (auto& e : str)
		{
			cout << e;
		}
		return on;
	}

>> 重载

istream& operator>>(istream& in, string& str)
	{

		str.clear();
		char ch = in.get();
		while (ch != ' ' && ch != '\n')
		{
			str += ch;
			ch = in.get();
		}
		return in;
	}

这里不能使用cin,因为cin不能读取空格和\n,只是使用cin.get(),
需要注意的是istream和ostream类型是在std中的

string的一些成员函数的现代写法

#include<iostream>
#include<string>

using namespace std;
namespace bit
{
	class String
	{
	public:
		String(const char* str)
		{
			_size = strlen(str);
			_capacity = _size;
			_str = new char[_size];
			strcpy(_str, str);
		}
		//现代写法拷贝构造
		String(const String& str)
		{
			String tmp(str._str);//构造一个新的
			Swap(tmp);//进行交换
			
		}
		void Swap(String& str)
		{
			std::swap(_str, str._str);
			std::swap(_size, str._size);
			std::swap(_capacity, str._capacity);
		}
		char* c_str()
		{
			return _str;
		}
		typedef char* iterator;
		
		iterator begin()
		{
			return _str;
		}
		iterator end()
		{	
			return _str+_size;
		}
		//现代写法赋值
		String& operator=(String str)//这里是传值
		{
			Swap(str);
			return *this;
		}


	private:
		size_t _size;
		size_t _capacity;
		char* _str;
	};
	ostream& operator<<(ostream& on, String& str)
	{
		for (auto e : str)
		{
			on << e;
		}
		return on;
	}
}

小知识

注意:类的静态成员是不算类的大小的,
当我们在Linux下和在window下计算string的大小是不一样的
window64位下:
在这里插入图片描述
可以看到在VS下是40,
Linux下:
在这里插入图片描述
大小是8,
在Visual Studio中,string的大小为40是因为Visual Studio的STL(标准模板库)实现中,string通常包含一个指向字符数据的指针,还有一些额外的元数据,比如长度、容量等信息。此外,STL的实现可能还包括一些用于优化和内存对齐的额外空间。因此,即使string中只包含很少的字符,它的大小也可能会比预期的要大。
另外,这个大小可能会根据编译器版本、操作系统和编译配置等因素而有所不同。
在Linux中string的成员只计算一个指向字符数据的指针,
在这里插入图片描述
引用计数:是为了实现写时拷贝的,用来记录资源使用者的个数。在构造时,将资源的计数给成1,每增加一个对象使用该资源,就给计数增加1,当某个对象被销毁时,先给该计数减1,然后再检查是否需要释放资源,如果计数为1,说明该对象时资源的最后一个使用者,将该资源释放;否则就不能释放,因为还有其他对象在使用该资源。
写时拷贝主要是为了解决内存的,前面深拷贝很好用,但是有时候深拷贝也会造成空间的浪费的缺陷,写时拷贝也是有自己的缺陷,
写时拷贝
写时拷贝的缺陷

相关推荐

  1. C++string模拟实现

    2024-04-21 20:12:04       18 阅读
  2. Cppstring模拟实现

    2024-04-21 20:12:04       30 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-04-21 20:12:04       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-21 20:12:04       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-21 20:12:04       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-21 20:12:04       18 阅读

热门阅读

  1. UML绘制

    2024-04-21 20:12:04       15 阅读
  2. 怎么直连某个服务器的dubbo服务

    2024-04-21 20:12:04       14 阅读
  3. stm32知识记录

    2024-04-21 20:12:04       16 阅读
  4. EXCEL VBA限制工作数据批号或者自定义规则完整

    2024-04-21 20:12:04       15 阅读