【C++】模拟实现String类

     String类时C++中非常重要的一个类,模拟实现String类涉及到浅拷贝,深拷贝的问题。

浅拷贝:在拷贝的时候,只是拷贝了指针的内容,而指针所指向的空间并没有变,两个指针指向同一块内存空间。在释放空间的时候,就会造成重复释放同一块内存空间而报错。

深拷贝:在拷贝的时候,开辟一块和原指针指向的空间相同大小的空间,使新增加的指针指向新的内存,这样在释放空间时,就不会出现重复释放了。

引用计数:前拷贝出现的问题是在拷贝构造函数及赋值运算符的重载,因此我们增加一个指针,当管理该空间的指针增加一个,我们将让这个变量增加1,当变量减为0时,我们再释放该空间。

由于在实现String类时浅拷贝存在问题,在此我们就直接用深拷贝和引用计数的方法实现String类

class String
{
public:
	friend ostream& operator<<(ostream& _cout, const String& s)
	{
		_cout << s._pStr;
		return _cout;
	}
	String(const char* pStr = "")
	{
		if (pStr == NULL)
		{
			_pStr = new char[1];
			*_pStr = '\0';
		}
		else
		{
			_pStr = new char[strlen(pStr) + 1];
			strcpy(_pStr, pStr);
		}
	}
	String(const String& s)//拷贝构造函数
		: _pStr(new char[strlen(s._pStr) + 1])
	{
		strcpy(_pStr, s._pStr);
	}
	~String()
	{
		if (_pStr)
		{
			delete[] _pStr;
			_pStr = NULL;
		}
	}
	String& operator=(const String& s)
	{
		if (this != &s)
		{
			char* Temp = new char[strlen(s._pStr) + 1];
			strcpy(Temp, s._pStr);
			delete[] _pStr;
			_pStr = Temp;
		}
		return *this;
	}
	bool operator>(const String& s)//重载>
	{
		char* s1 = _pStr;
		char* s2 = s._pStr;
		while (*s1 == *s2)
		{
			if (*s1 == '\0')
				return false;
			s1++;
			s2++;
		}
		if (*s1 > *s2)
			return true;
		return false;
	}
	bool operator<(const String& s)重载<
	{
		char* s1 = _pStr;
		char* s2 = s._pStr;
		while (*s1 == *s2)
		{
			if (*s1 == '\0')
				return false;
			s1++;
			s2++;
		}
		if (*s1 < *s2)
			return true;
		return false;
	}
	bool operator==(const String& s)重载==
	{
		char* s1 = _pStr;
		char* s2 = s._pStr;
		while (*s1 == *s2)
		{
			if (*s1 == '\0' && *s2 == '\0')
				return true;
			s1++;
			s2++;
		}
		return false;
	}
	bool operator!=(const String& s)重载!=
	{
		char* s1 = _pStr;
		char* s2 = s._pStr;
		if (s1 == s2)
			return false;
		return true;
	}
private:
	char *_pStr;
}
关于拷贝构造函数及赋值运算符的重载,我们还有几种简洁的实现方法:

	//注意此种方法,一定要在开始时将_pStr置为空指针,否则,程序可能会崩溃。
	//在VS2013中this->_pStr为0x0,所以不会出错,在VS2008中this->_pStr为0xcccccccc,会出错
	String(const String& s)//如果this指针不为0,交换后,tmp变为野指针,析构时程序崩溃
		: _pStr(NULL)      //而我们将_pStr初值置为NULL,交换后tmp._pStr也为0,析构时不会delete,不会出现问题
	{
		String tmp(s._pStr);
		swap(_pStr, tmp._pStr);
	}
	String& operator=(const String& s)
	{
		if (this != &s)
		{
			char* Temp = new char[strlen(s._pStr) + 1];
			strcpy(Temp, s._pStr);
			delete[] _pStr;
			_pStr = Temp;
		}
		return *this;
	}
	String& operator=(const String& s)//用s构造tmp对象,交换当前指针和tmp,返回*this
	{
		if (this != &s)
		{
			String tmp(s);//拷贝构造
			swap(_pStr, tmp._pStr);
		}
		return *this;
	}
	String& operator=(const String& s)
	{
		if (this != &s)
		{
			String tmp(s._pStr);//构造函数
			swap(_pStr, tmp._pStr);
		}
		return *this;
	}
	String& operator=(String s)//值传递,拷贝构造构建临时变量
	{
		swap(_pStr, s._pStr);
		return *this;
	}
引用计数:

class String
{
public:
	String(const char* pStr = "")
		:_count(new int(1))
	{
		if (NULL == pStr)
		{
			_pStr = new char[1];
			*_pStr = '\0';
		}
		else
		{
			_pStr = new char[strlen(pStr) + 1];
			strcpy(_pStr, pStr);
		}
	}
	String(const String& s)
		: _count(s._count)
		, _pStr(s._pStr)
	{
		(*_count)++;
	}
	String& operator=(const String& s)
	{
		if (this != &s)
		{
			if (0 == --(*_count))//s3=s2
			{
				delete[] _pStr;
				delete _count;
			}
			_pStr = s._pStr;//s2=s3
			_count = s._count;
			(*_count)++;
		}
		return *this;
	}
	~String()
	{
		if (0 == --(*_count) && _pStr)
		{
			delete[] _pStr;
			_pStr = NULL;
			delete _count;
			_count = NULL;
		}
	}
private:
	char* _pStr;
	int * _count;
};
利用引用计数的方法,虽然也可以完成,但存在线程安全的问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值