【C++】模拟实现String类

来源:互联网 发布:2020家居设计软件视频 编辑:程序博客网 时间:2024/06/07 03:04

     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')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;};
利用引用计数的方法,虽然也可以完成,但存在线程安全的问题。

原创粉丝点击