方案三

class String{    private:               char* _str;               size_t  _size;               size_t  _capacity;               int* _refCount;       //***};

方案三设置了一个int型的指针变量用来引用计数,每份内存空间对应一个引用计数,而不是每个对象对应一个引用计数,而且每块内存的引用计数互不影响,不会出现方案一和方案二出现的问题。

1.在实现赋值运算符重载要谨慎,不要遇到下图的情形

2.改变字符串的某个字符时要谨慎,不要遇到类似下图所遇到的问题。

如果多个对象都指向同一块内存,那么只要一个对象改变了这块内存的内容,那所有的对象都被改变了!!

可以用下图的形式改善这种问题:新设置一块内存来存要改变的对象

案例3我画的图较多,方便大家结合代码去理解 

class String{public:	String(char* str = "")    //不能strlen(NULL)	{		_refCount = new int(1);     //给_refCount开辟空间,并赋初值1		_size = strlen(str);		_capacity = _size + 1;		_str = new char[strlen(str) + 1];		strcpy(_str, str);	}	String(const String &s)	{		_refCount = s._refCount;		_str = s._str;		_size = strlen(s._str);		_capacity = _size + 1;		(*_refCount)++;      //拷贝一次_refCount都要加1			}		//要考虑是s1=s2时,s1原先不为空的情况,要先释放原内存	//如果要释放原内存时,要考虑它的_refCount减1后是否为0,为零再释放,否则其它对象指针无法再访问这片空间	String& operator=(String& s)  	{		if (_str!= s._str)		{			_size = strlen(s._str);			_capacity = _size + 1;			if (--(*_refCount) == 0)			{				delete[] _str;				delete _refCount;			}						_str = s._str;			_refCount = s._refCount;			(*_refCount)++;		}				return *this;	}	//如果修改了字符串的内容,那所有指向这块内存的对象指针的内容间接被改变	//如果还有其它指针指向这块内存,我们可以从堆上重新开辟一块内存空间,	//把原字符串拷贝过来	//再去改变它的内容,就不会产生链式反应	//  1.减引用计数  2.拷贝   3.创建新的引用计数	char& String::operator[](const size_t index) //参考深拷贝      	{		if (*_refCount==1)		{			return *(_str + index);		}		else		{			--(*_refCount);			char* tmp = new char[strlen(_str)+1];			strcpy(tmp, _str);			_str = tmp;			_refCount = new int(1);			return *(_str+index);		}	}	~String()	{		if (--(*_refCount)== 0)  //当_refCount=0的时候就释放内存		{			delete[] _str;			delete _refCount;			_str = NULL;			cout << "~String " << endl;		}		_size = 0;		_capacity = 0;	}private:    char* _str;      //指向字符串的指针    size_t  _size;      //字符串大小    size_t  _capacity;   //容量    int* _refCount;    //计数指针};

以下是其它方案链接地址:

方案一:

方案二:

方案四:(推荐)