实现字符串MyString

这篇博客详细介绍了如何实现一个自定义的C++字符串类`MyString`,包括其内部结构、内存管理、成员函数如`clear()`、`size()`、`reserve()`、`operator[]`等。此外,还涵盖了构造函数、赋值操作、输出流操作以及字符串拼接等操作。通过实例展示了类的使用,如创建字符串、遍历、输出等。
摘要由CSDN通过智能技术生成
#include <vector>
#include<iostream> //istream ,ostream
#include<assert.h>
#include<fstream>
using namespace std;
class MyString
{
private:
	struct StrNode
	{
		int ref;//引用计数(表示有多少个客户在使用)
		int len;//字符长度
		int capc;//容量
		char data[0];//柔性数组(要么给0,要么什么也不给)
	};
	enum{ALGIN=8};//枚举
private:
	StrNode* pstr;//结构类型的指针
	size_t round_up(size_t n)//对其方式的提升
	{
		return (n + ALGIN - 1) & ~(ALGIN - 1);
		//return ((n - 1) / ALGIN + 1) * ALGIN;   如:1,2,3,4,5,6,7,8=>8  ;  9,10,11,...,16=>16
		
	}
	static StrNode* M_Malloc(size_t size)//size为柔性数组所开辟的空间
	{
		//封装malloc,并对其尾部信息
		StrNode* s = (StrNode*)malloc(sizeof(StrNode) + sizeof(char) * size);
		if (nullptr == s)
		{
			exit(1);
		}
		return s;
	}
	static StrNode* M_Realloc(StrNode* p, size_t size)
	{
		StrNode* s = (StrNode*)realloc(p, sizeof(StrNode) + sizeof(char) * size);
		if (nullptr == s)
		{
			exit(1);
		}
		s->capc = size-1;
		return s;
	}
	static StrNode* cloneStrNode(StrNode* ps)//克隆
	{
		StrNode* s = M_Malloc(ps->capc + 1);
		memmove(s, ps, sizeof(StrNode) + ps->len + 1);
		s->ref = 1;
		s->len =ps->len;
		s->capc = ps->capc;
		return s;
	}
public:
	typedef char value_type;//值类型设置为char
	typedef char* iterator; //迭代器设置为char
	typedef const char* const_iterator;//常性迭代器,只能指向你,不能修改你
public:
	iterator begin()
	{
		return pstr->data;
	}
	iterator end()
	{
		return pstr->data + pstr->len;
	}
	const iterator begin() const
	{
		return pstr->data;
	}
	const iterator end() const
	{
		return pstr->data + pstr->len;
	}

public:
	void clear()  //清除是将引用计数降下来,当引用计数为0时,才有资格释放
	{
		if (nullptr != pstr && --pstr->ref == 0)
		{
			free(pstr);
		}
		pstr = nullptr;
	}
	//容量函数
	size_t size() const //字符串个数
	{
		//assert(pstr != nullptr);
		return (pstr != nullptr) ? pstr->len : 0;
	}
	size_t length() const { return size(); }
	bool empty() const{ return size() == 0; }
	size_t capacity() const
	{
		return (pstr != nullptr) ? pstr->capc : 0;
	}
	void reserve(size_t newsz);//保留存储函数
	//元素访问函数
	char& at(const int index) //写时拷贝
	{
		return operator[](index);
	}

	const char& at(const int index) const
	{
		return operator[](index);
	}
	char& operator[](const int index)//重载下标运算符
	{
		assert(pstr != nullptr && index >= 0 && index < pstr->len);
		if (pstr->ref > 1)
		{
			pstr->ref -= 1;
			pstr = cloneStrNode(pstr);
		}
		else
		{
			return pstr->data[index];
		}
	}
	const char& operator[](const int index) const
	{
		assert(pstr != nullptr && index >= 0 && index < pstr->len);
		return pstr->data[index];
	}

	char& front()//访问第一个字符
	{
		return at(0);
	}
	const char& front() const
	{
		return at(0);
	}
	char& back()//访问最后一个字符
	{
		return at(pstr->len - 1);//return at(size()-1);
	}
	const char& back()const
	{
		return at(size() - 1);
	}
	const char* c_str() const
	{
		return (pstr == nullptr) ? nullptr : pstr->data;
	}
	const char* data() const
	{
		return (pstr == nullptr) ? nullptr : pstr->data;
	}
	char* data()
	{
		return (pstr == nullptr) ? nullptr : pstr->data;
	}

public:
	MyString(const char* p = nullptr) :pstr(nullptr)//构造函数,并对其初始化
	{
		if (nullptr != p)
		{
			int n = strlen(p);
			int total = round_up(2 * n);//提升为8的倍数
			//int total = 2* n;
			pstr = M_Malloc(total);//total为柔性数组的大小
			pstr->ref = 1;
			pstr->len = n;
			pstr->capc = total - 1;
			strcpy_s(pstr->data, total, p);
		}

	}
	~MyString() //析构函数
	{
		/*if (nullptr != pstr && --pstr->ref == 0)//表示指向了一个柔性数组这样的结构,且引用计数为0(该字符串已经没人使用)
		{
			free(pstr);
		}
		pstr = nullptr;
		*/
		clear();
	}
	MyString(const MyString& s) :pstr(s.pstr)//浅拷贝构造函数(当引用计数为0时,才会消亡)
	{
		if (pstr != nullptr)
		{
			pstr->ref += 1;
		}
	}
	MyString& operator=(const MyString& sc) //赋值函数
	{
		if (this == &sc||this->pstr==sc.pstr) return *this;//自己给自己赋值,没有任何意义
		clear();//s1=s2,赋值之前,先将s1清除
		pstr = sc.pstr;
		if (pstr != nullptr)
		{
			pstr->ref += 1;
		}
		return *this;
	}
	MyString(MyString&& sc):pstr(sc.pstr)//移动构造(将堆区空间的资源给另一个空间,引用计数不会发生变化)
	{
		sc.pstr = nullptr;
	}
	MyString& operator=(MyString&& sc)//移动赋值
	{
		if (this == &sc) return *this;
		clear();//先将自己的资源释放掉
		pstr = sc.pstr;
		sc.pstr = nullptr;//移动之后,资源空了,然后将其置空
		return *this;
	}//s1=std::move(s2);

	ostream& operator<<(ostream& out) const //输出流
	{
		if (pstr != nullptr)
		{
			out << pstr->data;
		}
		return out;
	}

	void Print() const
	{
		if (pstr != nullptr)
		{
			cout << pstr->data << endl;
		}
	}
	MyString operator+=(const MyString& sc) ;//字符串对象相加
	MyString operator+=(const char* p);//字符串常量相加
	MyString& operator += (const char ch)//追加字符
	{
		char str[2] = { ch,'\0' };
		if (pstr == nullptr) 
		{
			*this= MyString(str);
		}
		else if(pstr->ref==1)
		{
			if (pstr->capc - pstr->len >= 0)
			{
				pstr->data[pstr->len] = ch;
				pstr->data[++pstr->len] = '\0';
			}
			else
			{
				pstr = M_Realloc(pstr, round_up(pstr->len * 2));//扩容
			}
		}
		else
		{
			pstr->ref -= 1;
			pstr = cloneStrNode(pstr);
			if (pstr->capc - pstr->len >= 0)
			{
				pstr->data[pstr->len] = ch;
				pstr->data[++pstr->len] = '\0';
			}
			else
			{
				pstr = M_Realloc(pstr, round_up(pstr->len * 2));//扩容
			}

		}
		return *this;
	}
};
MyString operator+(const char* p, const MyString& sc) ;//字符常量和字符串对象相加

ostream& operator<<(ostream& out, const MyString& s)//全局输出函数
{
	s << out;//s.operator<<(out); operator<<(s,out);
	return out;
}
int main()
{
	MyString s1("yhping");
	MyString::iterator it = s1.begin();
	for (; it != s1.end(); ++it)
	{
		//cout << *it << endl;
	}
	for (char ch:s1)//范围for
	{
		cout << ch << endl;
	}
	size_t n = s1.size();
	for (int i = 0; i<n; i++)
	{
		cout << s1.at(i) << " ";
		//cout << s1[i] << "  ";
	}
	s1.Print();
	const char* str = s1.c_str();
	if (str != nullptr)
	{
		cout << str << endl;
	}
	return 0;
}

运行结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值