C++——string的深拷贝与浅拷贝

在c++中,基本所有的类都要考虑深拷贝,浅拷贝与写时拷贝,根据不同的定义,选择适合自己的拷贝方式。时间类就可以用浅拷贝,而二叉树,string类就需要深拷贝。
string类在vs编译器下使用的深拷贝,在Linux下使用的浅拷贝。
为什么会存在深浅拷贝的问题呢?
string的浅拷贝是让两个不同的指针指向同一块空间,而这在析构的时候会出现将一块空间释放两次,程序会崩溃,因此我们才需要进行深拷贝,即第二个指针开辟和第一个指针一样大小空间,然后将内容复制过去。
深拷贝:

class string
{
public:
	string(char* pstr)    //构造函数
		:str(new char[strlen(pstr) + 1])   //开辟新的空间
	{
		if (pstr == NULL)//
		{
			str = new char[1];    //开辟一个 存放‘\0’
			*str = '\0';
		}
		else
		{
			str = new char[strlen(pstr) + 1];
			for (size_t i = 0; i < strlen(pstr); i++)  //深复制
			{
				str[i] = pstr[i];
            }
			//strcpy(str,pstr);
			//memcpy(str,pstr,strlen(pstr)+1);浅复制
		}
	}
	//拷贝构造函数
	string(const string& pstr)
		:str(new char[strlen(pstr.str)+1])
	{
		for (size_t i = 0; i < strlen(pstr.str); i++)
		{
			str[i] = pstr.str[i];
		}
		//strcpy(str,pstr.str);
		//memcpy(str,pstr.str,strlen(pstr.str)+1);
	}
	//赋值运算符重载
	string& operator = (const string & pstr)
	{
		if (&str == &pstr.str)     //检查是否是自己给自己赋值
			return *this;
		delete[] str;             //释放临时空间
		str = new char[strlen(pstr.str) + 1];
		for (size_t i = 0; i < strlen(pstr.str); i++)
		{
			str[i] = pstr.str[i];
		}
		//strcpy(str,pstr.str);
		//memcpy(str,pstr.str,strlen(pstr.str)+1);
		return *this;
	}
	/*现代写法: 根据拷贝构造函数让系统自己开辟空间 
	拷贝构造函数
	string(const string& pstr)
	     :str=null;    必须置为空,要不然访问地址非法化
	     {    
	         string tmp (pstr);
	         swap(tmp.str,str);
	         return *this;
	     }
	赋值运算符重载
	string& operator = (const string& pstr )
	{
		string tmp(pstr);
		swap(tmp.str, str);
		return *this;
     }*/
	//析构函数
	~string()
	{
		delete[] str;
		str = NULL;
	}

private:
	char* str;

};
int main()
{
	string a ("12345");
	string b(a);
	cout << b << endl;
}

浅拷贝,当我们需要改变新的空间的内容的时候,才会重新开辟空间呢?
1)判断空间使用的次数来选择析构,增加一个类成员 count,但是这样造成的后果是每一个成员都有一个不同的count 在析构的时候就很混乱还是会出错
2)然后呢我们会想到使用静态成员的办法,因为此时 static int count 是放在静态区,它是所有对象共享的,不会为每个对象单独生成一个count,可是当我们有多个不同的成员共同管理一块空间,而此时我们又用构造函数创建一个对象时候,count又会变为1,所以这种方法还是不行 。
3)使用引用计数,把引用计数放在字符串的前四个字节里,每个创建出来的对象都有不同的引用计数

class string
{
public:
	string(char* pstr)    //构造函数
		:str(new char[strlen(pstr) + 1+4])//多开辟的4个字节存放引用计数
	{
		if (pstr == NULL)
		{
			str = new char[1];
			*str = '\0';
		}
		else
		{
			str = new char[strlen(pstr) + 1+4];
			int* count = (int* )str;
			*count = 1;
			count ++;  //后移拷贝数据
			str = (char*)count;
			for (size_t i = 0; i < strlen(pstr); i++)  //深复制
			{
				str[i] = pstr[i];
            }
			//strcpy(str,pstr);
			//memcpy(str,pstr,strlen(pstr)+1);浅复制
		}
	}
	//拷贝构造函数
	string(const string& pstr)
    {
		str = pstr.str;
		int * count = (int *)(str-4) ;
		++*count;
		
	}
	//赋值运算符重载
	string& operator = (const string & pstr)
	{
		if (&str == &pstr.str)
			return *this;
		destroy();//判断是否释放空间
		str = pstr.str;
		int * count = (int *)(str-4) ;
		++*count;
	}
void destroy()
{
    int * count = (int *)(str-4); //获取引用计数
    if(*count == 1)
    {
       delete[](str-4);
       str = NULL;
    }
    else
      --*count;
}
//析构函数
~string()
{
   destroy();
}

private:
	char* str;
    int * count;
};


写时拷贝:
在浅拷贝中,假设有多个名称引用了同一个字符串,当其中一个需要修改字符串时,这就会导致引用的值发生改变,这明显不是我们所期望的,所以出现了写时拷贝,(可能会修改字符串的时候使用深拷贝将其与大部队分离,这样就保护了其他引用成员)
则我们只需要重载[] 就可以实现

const string& operator[]const 
{
        string tmp(pstr);
		swap(tmp.str, str);
		return *this;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
深拷贝浅拷贝是两种不同的拷贝方式,用于复制对象。在C++中,当对含有指针成员的对象进行拷贝时,需要考虑使用深拷贝来避免内存重复释放的问题。 浅拷贝只是简单地将原对象的值赋给新对象,包括指针成员的值也只是简单地复制指针的地址,这导致新对象和原对象共享同一份资源,当其中一个对象释放资源后,另一个对象仍然会引用到已释放的内存,导致错误。在深拷贝中,需要自定义拷贝构造函数,以便在拷贝对象时,重新分配新的内存空间,并将原对象指针成员指向的数据复制到新的内存中。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [C++——深拷贝浅拷贝](https://blog.csdn.net/weixin_59179454/article/details/124935417)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [C++浅拷贝深拷贝](https://blog.csdn.net/qq_42174306/article/details/122882267)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值