方案三

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


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

写时拷贝(方案三)_第1张图片



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

写时拷贝(方案三)_第2张图片


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

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

写时拷贝(方案三)_第3张图片

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

写时拷贝(方案三)_第4张图片

案例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;    //计数指针
};

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

方案一:

http://iynu17.blog.51cto.com/10734157/1755179

方案二:

http://iynu17.blog.51cto.com/10734157/1755185

方案四:(推荐)

http://iynu17.blog.51cto.com/10734157/1755213