C嘎嘎程序设计------STL string类的模拟实现

前言

通过实现常用的string类的函数接口进一步了解string类,能够使我们对string类理解更深。从而更好的运用string。

成员变量

private:
	char* _str;
	int _size;
	int _capacity;
	const static size_t npos = -1;

四大天选之子

默认构造函数

string(const char* str = "")
		:_size(strlen(str))
{
	_capacity = _size == 0 ? 4 : _size;
	//需要多开一个空间放'\0'
	_str = new char[_capacity + 1];
	strcpy(_str, str);
}

拷贝构造函数
需要new一块空间拷贝,发生值拷贝则会出现编译器会调用两次析构函数报错

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

析构函数

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

赋值重载
这个上面坑很多
1.首先需要考虑被赋值的空间是比要赋值的空间大?相等?还是小?
2.如果比较小,要扩容的话,不能先将原来的空间释放掉,再来new空间,万一new失败抛异常了呢,那原来的空间被释放掉了就有问题了。
3.如果是str1=str1呢?如果不用创建一个变量来记住_str,像我下面的代码开完空间后要进行拷贝的时候,拷贝下来的全部是随机值。没有出现拷贝下来是随机值,那么自己赋值自己,还要再开辟一块空间,使得效率变得很低。

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

运算符重载

[ ]重载 因为可读性的原因,使得访问string的元素用得最多是操作符[ ]一般对于获取值的函数常常加const,防止出现权限放大的问题。

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

大于、小于、等于之类的运算符重载。只要实现一两个,其他相似的复用即可

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

bool operator>(const string& str) const
{
	return strcmp(_str, str._str) > 0;
}
bool operator >=(const string& str) const
{
	return *this > str || *this == str;
}

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

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

获取大小

获取size值

int size()const
{
	return _size;
}

获取capacity值

int capacity()const
{
	return _capacity;
}

获取字符串地址

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

扩容

reserve

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

resize在实现的时候有比较多的点需要注意的,需要分三种情况来处理
1.要改变的大小在小于size时,相当于删除元素。
2.大于size小于capacity时,相当于时初始化>=size且<=capacity部分。
3.大于capacity时,相当于扩容,且初始化>=size且<=capacity部分

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

修改string

** insert函数**
有分两种,一种插入字符,另一种插入字符串

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

	int end = _size;
	int begin = pos;
	while (begin <= end)
	{
		_str[end + 1] = _str[end];
		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+1;
	int size = _size;
	while (end>pos+len)
	{
		_str[end-1] = _str[size];
		end--;
		size--;
	}
	//拷贝
	memcpy(_str+pos, str, len);
	_size += len;
	return *this;
}

删除数据Erase
要分两种情况,一种是从pos起删除的数据<_size, 另一种则是>=_size

string& Erase(size_t pos, size_t num = npos)
{
	assert(pos < _size);
	if (num == npos||pos+num>_size)
	{
		_str[pos] = '\0';
		_size = pos;
	}
	else
	{
		strcpy(_str+pos, _str+pos+num);
		_size-=num;
	}
	return *this;
}

push_back ---- 尾插字符

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

append ---- 追加字符串

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

	strcpy(_str + _size, str);
	_size += len;
}

运算符重载+= ---- 追加字符或者字符串
平时更加推荐用这个使可读性变高。

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

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

迭代器

这边采用的是SGI的版本,与VS使用的版本不同,采用的是原生指针作为迭代器

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类的实现并不是很难,但是有许多细节需要注意,但是自己实现一遍,对于string的理解比仅仅调用其成员函数来完成稍微滴更上一层了。

  • 9
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值