深拷贝与写实拷贝----string

摘要


学过或者了解过C++都知道,,,在C++中面向对象实现一个类 、、、的时候必须要考虑的就是

【深浅拷贝】的问题 ??

所以我写了这篇文章来简要的讲述一下C++中深浅拷贝的问题以及由此引发的    另一个  概念【写实拷贝】

概念的解析

所谓的深浅拷贝就是 

C++中;;;;;定义一个类的时候;;;

其拷贝构造函数、、、还有赋值运算符的重载   的不同的实现方法;;;

当一个类的成员变量中带有的是  指针;;;


当使用这个类对象拷贝生成一个对象的的时候、、、如果直接赋值的话,,,,,类析构的时候就会出现问题;;;

所以在这种时候 我们就需要来考虑深拷贝的问题;;;;

关于深拷贝的问题、、、大致主要有两种的方法:
方法1、
直接重新申请一段相同大小的空间、、、并赋值成相同的值  ;;;

这就是直接的深拷贝;

方法2、
在类的成员变量中加上一个   【引用计数 】用来表示当前有多少个对象在公用一段空间 

类析构时、(要是引用计数为1  直接释放这段空间 )(否则的话就将这个对象的成员变量的指针置为NULL)

这种方法  就是  带有引用计数的浅拷贝的  实现深拷贝

【灰常的重要】

但是上述的方法2     虽然实现了   深拷贝 、、、但是还遗留了一个很大的问题;;;

假设有 4  个string类的对象     a    b   c     d;公用的是 同一段的空间 

现在要对  对象a   的内容进行修改、、、、
但是要是修改了  a的 内容   b  c  d的内容也会被修改(因为它们用的是同一段空间)

所以也就出现了  【写实拷贝】这个   概念》》》》

当遇到上述这种情况下、、、、谁  改变 就对谁进行拷贝   ------这就是 写实拷贝


上述的两种方法
Windows系统下的编程环境使用的是  方法1
Linux系统下是用的是 方法2




通常情况下、、、、、我们都是使用的是  string来演示实现     深拷贝、、、与写实拷贝的

代码的实现

下面我来实现这段代码的实现

#pragma  once 
#include <assert.h>
//说道string类的两个主要考点就是 
//深拷贝
//浅拷贝   写实拷贝 ()


//深拷贝
class String 
{
public:
	String(const  char  * str = "")
	{
		//要是传进来的字符串为 NULL
		if(str == NULL)
		{
			//我们需要创建一个内容为 /0的字符串
			_str  =new char [1];
			*_str  = '/0';
		}
		else
		{
			//否则,,,开辟一个长度为 str长度+1; 
			_str  = new char [strlen(str)+1];
			strcpy(_str,str);  
		}
	}

	//深拷贝的拷贝构造函数 
	//String(const  String &  str)
	//	:_str(new char[strlen(str._str)+1])
	//{
	//	//先为字符串开辟一个空间
	//	//将内部的数据拷贝
	//	strcpy(_str,str._str);
	//}

	//简介版 的拷贝构造函数 

	String (const String &  str)
		:_str(NULL)//现将当前的对象的字符串的指针赋为空 ,,,必须要写 
	{
		//使用的是 str内部的字符串的指针,,来构造一个新的对象 str1;
		String  str1(str._str);
		//将当前的对象的_str  与  重新生成的新对象的_str 交换
		swap(_str,str1._str);
	}
	
	//深拷贝的赋值运算符的重载
	//String & operator = (const  String  &  str)
	//{
	//	if(this!= &str)
	//	{
	//		//开辟一个空间 
	//		char *  tmp  =new char[strlen(str._str)+1];
	//		//将原来的空间释放
	//		delete[]_str;
	//		//将内容拷贝到所开辟的位置 
	//		strcpy(tmp,str._str);
	//		//将开辟的空间给当前的类
	//		_str = tmp;
	//	}
	//	return *this;
	//}

	//简介版 的赋值运算符的重载
	String &    operator =(const  String  &  str)
	{
		//防止自己给自己赋值
		if(this  != &  str)
		{
			String str1(str);//使用拷贝构造函数  ,,,来生成一个新的对象 
			//先将当前对象的_str释放 ,,,,并且赋值成 NULL
			delete[]  _str;
			_str = NULL;
			swap(_str,str1._str);
		}
		return  *this;
	}
	~String()
	{
		if(_str != NULL)
		{
			delete []  _str;
		}
		_str   =NULL;
	}


	//重载【】
	char & operator[](size_t n)
	{
		assert(n < strlen(_str) );
		return  *(_str+n);
	}
protected:
	char  *_str;
};



//引用计数的浅拷贝     写实拷贝
class StringS
{
public:
	StringS(const  char  * str = "")
	{
		//要是传进来的字符串为 NULL
		if(str == NULL)
		{
			//我们需要创建一个内容为 /0的字符串
			_str  =new char [1];
			*_str  = '/0';
		}
		else
		{
			//否则,,,开辟一个长度为 str长度+1; 
			_str  = new char [strlen(str)+1];
			strcpy(_str,str);  
		}
		_count = new int(1);
	}

	//拷贝构造函数 
	StringS(const  StringS &  str)
		:_str (str._str)
		,_count(str._count)
	{
		(*_count)++;
	}
	//带有引用计数的赋值运算符的重载 
	StringS &  operator=( const StringS  &  str)
	{
		if(_str !=  str._str)
		{
			if(*_count == 1)
			{
				delete[] _str;
				_str  =  str._str;
			}
			else
			{
				(*_count)--;
				_str  = str._str;
			}
			_count  = str._count;
			(*_count) ++;
		}
		return  *this;
	}
	~StringS()
	{
		if(*_count == 1)
		{
			delete[] _str;
			delete _count;
		}
		else
		{
			(*_count) --;
		}
		_str = NULL;
		_count =NULL;
	}


	//写实拷贝 
	//当某个对象要进行 写的话   ,,,就要对其 单独进行拷贝 
	char & operator[](size_t  n)
	{
		assert(n < strlen(_str) );
		if(*_count != 1)//如果这个数 多个 对象使用的话 
		{
			char  *  tmp  = new  char[strlen(_str)+1];
			strcpy(tmp,_str);
			_str  =  tmp;
			(*_count)--;
			_count  = new int(1);
		}
		return *(_str+n);
	}
protected:
	char *  _str;
	int  *  _count ;//表示的是 引用计数

};
void testString()
{
	String  st(NULL);
	String  st1;
	String  st2("we are happy");
	String  st3(st2);
	st1 = st3;
}
void testStringS()
{
	StringS  st(NULL);
	StringS  st1;
	StringS  st2("we are happy");
	StringS  st3(st2);
	st1 = st3;
	st2[2];
}




















  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值