String类的模拟实现

一、经典String类的问题

首先,看一段代码

class string
{
public:
 /*string()
 :_str(new char[1])
 {*_str = '\0';}
 */
 //string(const char* str = "\0") 错误示范
 //string(const char* str = nullptr) 错误示范
 string(const char* str = "")
 {
 // 构造string类对象时,如果传递nullptr指针,认为程序非法,此处断言下
 if(nullptr == str)
 {
 assert(false);
 return;
 }
 
 _str = new char[strlen(str) + 1];
 strcpy(_str, str);
 }
 
 ~string()
 {
 if(_str)
 {
 delete[] _str;
 _str = nullptr;
 }
 }
 
private:
 char* _str;
};
// 测试
void Teststring()
{
string s1("hello bit!!!");
 string s2(s1);
}

在这里插入图片描述
说明:上述string类没有显式定义其拷贝构造函数与赋值运算符重载,此时编译器会合成默认的,当用s1构造s2时,编译器会调用默认的拷贝构造。最终导致的问题是,s1、s2共用同一块内存空间,在释放时同一块空间被释放多次而引起程序崩溃,这种拷贝方式,称为浅拷贝
深拷贝和浅拷贝的示意图大致如下:
在这里插入图片描述

1,浅拷贝

浅拷贝:也称位拷贝,编译器只是将对象中的值拷贝过来。如果对象中管理资源,最后就会导致多个对象共享同一份资源,当一个对象销毁时就会将该资源释放掉,而此时另一些对象不知道该资源已经被释放,以为还有效,所以 当继续对资源进项操作时,就会发生发生了访问违规。
当我们把一个对象赋值给一个新的变量时,赋的其实是该对象的在栈中的地址,而不是堆中的数据。也就是两个对象指向的是同一个存储空间,无论哪个对象发生改变,其实都是改变的存储空间的内容,因此,两个对象是联动的。

浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),拷贝的就是内存地址 ,因此如果其中一个对象改变了这个地址,就会影响到另一个对象。即默认拷贝构造函数只是对对象进行浅拷贝复制(逐个成员依次拷贝),即只复制对象空间而不复制资源。

2,深拷贝

一个引用对象一般来说由两个部分组成:一个具名的Handle,也就是我们所说的声明(如变量)和一个内部(不具名)的对象,也就是具名Handle的内部对象。它在Manged Heap(托管堆)中分配,一般由新增引用对象的New方法是进行创建。深拷贝是指源对象与拷贝对象互相独立,其中任何一个对象的改动都不会对另外一个对象造成影响。举个例子,一个人名叫张三,后来用他克隆(假设法律允许)了另外一个人,叫李四,不管是张三缺胳膊少腿还是李四缺胳膊少腿都不会影响另外一个人。比较典型的就是Value(值)对象,如预定义类型Int32,Double,以及结构(struct),枚举(Enum)等

#include<iostream>

using namespace std;
class Pata {
private:
	int a;
	
public:
	Pata(int a) {
		this->a = a; 	
	}
	Pata(Pata& ast) {
		this->a = ast.a;	
	}
};
int main() {
	Pata s1(2);
	Pata s2(s1);
	
	return 0;

}

在这里插入图片描述
this和ast地址不同
对象作为函数参数传递时,调用拷贝构造函数。
Pata(Pata& ast){} //系统默认另开辟一片空间,把ast复制到这片空间中去
如果改变s2的值不会改变s2的值。

二、现代写法版的string类

现代写法:借助中间变量,交换指针
在这里插入图片描述

#include<iostream>
#include<assert.h>
using namespace std;

namespace st {
	class string {
	private:
		char* _str;
		size_t _size;
		size_t  _capacity;
		static const size_t npos;
	public:
		void swap(string& st) {
			::swap(_str, st._str);
			::swap(_size, st._size);
			::swap(_capacity, st._capacity);
		}
	string(const char* st=" ") {
			_size = strlen(st);
			_capacity = _size;
			_str = new char[_capacity+1];
			strcpy(_str, st);
		}//构造函数采用深拷贝
		//拷贝构造的现代写法
		//s2(s1)---
		string(const string& st)
			:_str(nullptr)//s是局部对象出了作用域这个空
			//间就会释放,但不能对随机指向的空间释放
			,_size(0)
			,_capacity(0)
		{
			string s(st._str);//s这临时变量指向st._str
			swap(s);
		}
			}
			//传统写法
	/*	string(const string & st):
			_str(new char[strlen(st._str)+1])  {
			
			strcpy(_str, st._str);
			
		}*/
		//重载函数现代写法
		//s1=s2
		string& operator=(string st) {
			this->swap( st);
			return *this;
		}
		//传统写法
		/*	string& operator=(const string &st) {
			if (this!= &st) {
				delete[] _str;
				_str = new char[strlen(st._str) + 1];
				strcpy(_str, st._str);
			}
			return *this;
			
		}*/
		};

三、传统String类的模拟实现

传统写法:老老实实开辟空间并复制内容

1、迭代器

指针是良好的迭代器

		/*typedef char* iterator;
		iterator begin() {
			return _str;
		}
		iterator end() {
			return _str+_size;
		}*/
		typedef const char* iterator;
		iterator begin() const{ 
			return _str;
		}
		iterator end() const {
			return _str + _size;
		}

这里使用迭代器实现遍历打印

void print(const st::string& s ) {
	st::string::iterator it = s.begin();
	while (it<s.end()) {
		cout << *it;
		++it;
	}
		}

}

2、operator[]

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

3、size()

 size_t size() {
			return _size;
		}

4、c_str()

const char* c_str() {
			return _str;
		}

6、operator=()

//现代写法
		//s1=s2
		string& operator=(string st) {
			this->swap( st);
			return *this;
		}
	/*	string& operator=(const string &st) {
			if (this!= &st) {
				delete[] _str;
				_str = new char[strlen(st._str) + 1];
				strcpy(_str, st._str);
			}
			return *this;
			
		}*/

7、reserve

void reserve(size_t n) {
			if (n > _capacity) {
				char* tem = new char[n+1];
				strcpy( tem,_str);
				delete[]_str;
				_str = tem;
				_capacity = n;
			}
			
		}
		void resize(size_t n, char ch = '\0') {
			if (n < _size) {
				_str[n] = '\0';
				_size = n;
			}
			else  {
				if (n > _capacity) {
					reserve(n);
				} 
				for (size_t i = _size; i < n; i++) {
					_str[i] = ch;

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

8、push_back

void push_back(char ch) {
			
			if (_size == _capacity) {
				reserve(2 * _capacity);
			}
			_str[_size] = ch;
			++_size;
			_str[_size] = '\0';
		}

9、append

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

10、operator+=

}
		string& operator+=(char s) {
			push_back(s);
			return *this;
		}
		string& operator+=(const string &ss) {
			append(ss._str);
			return *this;
		}

11、insert

void insert(size_t n,char ch) {
			if (_size == _capacity) {
				size_t capacity =( _capacity == 0) ? 8 : _capacity * 2;
				reserve(capacity);
			}
			int end = _size+1;
			while (n<end) {
				_str[end] = _str[end-1];
				--end;
			}
			_str[n] = ch;
			_size++;
		}
			void insert(size_t n, const char *ch) {
				size_t len = strlen(ch);
				if (_size + len > _capacity) {
					reserve(_size + len);
				}
				size_t end = _size+len;
				while (end >= n + len) {
					_str[end] = _str[end - len];
					--end;
				}
				strncpy(_str + n, ch,len );
				_size += len;
		}

12、operator>

bool operator>(string s1, string s2) {
		size_t i = 0, j = 0;
		while (i < s1.size() && s2.size()) {
			if (s1[i] > s2[j]){
					return true;
			}
			else if (s1[i] < s2[j]) {
				return false;
			}
			else {
				i++; j++;
			}
		}
		if (i < s1.size()) {
			return true;
		}
		else if (j < s2.size()) {
			return false;
		}
		else {
			return true;
		}
	}

13、全部代码

#pragma warning(disable:4996)
#include<iostream>
#include<assert.h>
using namespace std;

namespace st {
	class string {
	private:
		char* _str;
		size_t _size;
		size_t  _capacity;
		static const size_t npos;
	public:
		//指针是天然的迭代器
		/*typedef char* iterator;
		iterator begin() {
			return _str;
		}
		iterator end() {
			return _str+_size;
		}*/
		typedef const char* iterator;
		iterator begin() const{ 
			return _str;
		}
		iterator end() const {
			return _str + _size;
		}
		string(const char* st=" ") {
			_size = strlen(st);
			_capacity = _size;
			_str = new char[_capacity+1];
			strcpy(_str, st);
		
		}
		//拷贝构造的现代写法
		//s2(s1)---
		string(const string& st)
			:_str(nullptr)//s是局部对象出了作用域这个空间就会释放,但不能对随机指向的空间释放
			,_size(0)
			,_capacity(0)
		{
			string s(st._str);//s这临时变量指向st._str
			swap(s);
		}
	/*	string(const string & st):
			_str(new char[strlen(st._str)+1])  {
			
			strcpy(_str, st._str);
			
		}*/
		char & operator[](size_t i) {
			assert(i < _size);
			return _str[i];
		}
		size_t size() {
			return _size;
		}
		~string() {
			delete[] _str;
		}

		const char* c_str() {
			return _str;
		}
		//现代写法
		//s1=s2
		string& operator=(string st) {
			this->swap( st);
			return *this;
		}
	/*	string& operator=(const string &st) {
			if (this!= &st) {
				delete[] _str;
				_str = new char[strlen(st._str) + 1];
				strcpy(_str, st._str);
			}
			return *this;
			
		}*/
		void reserve(size_t n) {
			if (n > _capacity) {
				char* tem = new char[n+1];
				strcpy( tem,_str);
				delete[]_str;
				_str = tem;
				_capacity = n;
			}
			
		}
		void resize(size_t n, char ch = '\0') {
			if (n < _size) {
				_str[n] = '\0';
				_size = n;
			}
			else  {
				if (n > _capacity) {
					reserve(n);
				} 
				for (size_t i = _size; i < n; i++) {
					_str[i] = ch;

				}
				_str[n] = '\0';
				_size = n;
			}
		
		}
		void push_back(char ch) {
			
			if (_size == _capacity) {
				reserve(2 * _capacity);
			}
			_str[_size] = ch;
			++_size;
			_str[_size] = '\0';
		}
		void append(const char* ch) {
			size_t len = strlen(ch) + 1;
				if (_size +len> _capacity) {
					reserve(len+_size);
				}
				strcpy(_str + _size, ch);
				_size += len;
		}
		string& operator+=(char s) {
			push_back(s);
			return *this;
		}
		string& operator+=(const string &ss) {
			append(ss._str);
			return *this;
		}
		void swap(string& st) {
			::swap(_str, st._str);
			::swap(_size, st._size);
			::swap(_capacity, st._capacity);
		}
		void insert(size_t n,char ch) {
			if (_size == _capacity) {
				size_t capacity =( _capacity == 0) ? 8 : _capacity * 2;
				reserve(capacity);
			}
			int end = _size+1;
			while (n<end) {
				_str[end] = _str[end-1];
				--end;
			}
			_str[n] = ch;
			_size++;
		}
			void insert(size_t n, const char *ch) {
				size_t len = strlen(ch);
				if (_size + len > _capacity) {
					reserve(_size + len);
				}
				size_t end = _size+len;
				while (end >= n + len) {
					_str[end] = _str[end - len];
					--end;
				}
				strncpy(_str + n, ch,len );
				_size += len;
		}
			void exit(size_t np,size_t npo=npos) {
				if (npo==npos||np + npo > _size) {
					_str[np] = '\0';
					_size = np;
				}
				else {
					strcpy(_str + np, _str + np + npo);
					_size -= npo;
				}
			}
			size_t find(char ch, size_t p = 0) {
				for (size_t i = 0; i < _size; i++) {
					if (_str[i] == ch) {
						return i;
					}
				}
				return npos;
			}
			size_t find(const char* ch, size_t p = 0) {
				const char* ret = strstr(_str + p, ch);
				if (ret == nullptr)
				{
					return npos;
				}
				else
				{
					return ret - _str;
				}
			}
	};
	const size_t string::npos = -1;
	bool operator>(string s1, string s2) {
		size_t i = 0, j = 0;
		while (i < s1.size() && s2.size()) {
			if (s1[i] > s2[j]){
					return true;
			}
			else if (s1[i] < s2[j]) {
				return false;
			}
			else {
				i++; j++;
			}
		}
		if (i < s1.size()) {
			return true;
		}
		else if (j < s2.size()) {
			return false;
		}
		else {
			return true;
		}
	}
	ostream& operator<<(ostream& out, string& s)
	{
		for (size_t i = 0; i < s.size(); ++i)
		{
			out << s[i];
		}

		return out;
	}
	istream& operator>>(istream& in, string& s)
	{
		s.resize(0);
		char ch;
		while (1)
		{
			//in>>ch;
			in.get(ch);
			if (ch == ' ' || ch == '\n')
			{
				break;
			}
			else
			{
				s += ch;
			}
		}

		return in;
	}

	bool operator==(string &s1, string &s2) {
		size_t i = 0, j = 0;
		while (i < s1.size() && s2.size()) {
			if (s1[i] > s2[j]) {
				return false;
			}
			else if (s1[i] < s2[j]) {
				return false;
			}
			else {
				i++; j++;
			}
		}
		if (i == s1.size()&& j ==s2.size()) {
			return true;
		}
		
		else {
			return false;
		}
	}
void print(const st::string& s ) {
	st::string::iterator it = s.begin();
	while (it<s.end()) {
		cout << *it;
		++it;
	}
		}

}
int main() {
	st::string s1("123456");
	st::string s2=s1;
	//s1.exit(2, 3);
	//print(s1);
	cout << s2;
	if (s1 == s2) {
	
		cout << "ok";
	}
	else {
		cout << "no";
	}
	return 0;
}
  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

自首的小偷

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值