深拷贝 浅拷贝 引发的写时拷贝

从一个例子说明浅拷贝是什么

#include <iostream>
using namespace std;

class string
{
public:
	string(const char *str="")
	{
		if (str == NULL)
		{
			data = new char[1];
			*data = '\0';
		}
		else
		{
			data = new char(strlen(str) + 1);
			strcpy(data, str);
		}
	}
	~string()
	{
		delete[]data;
		data = NULL;
	}
private:
	char *data;
};

当类中的私有数据  有指针  并且如果让程序默认生成 拷贝构造和 赋值方法   会发生浅拷贝现象 ,即

void main()
{
	String s1("hello");
	String s2 = s1;
}

默认的拷贝构造 只拷贝指针的指向,就是 s1和s2现在都指向同一块存着?“hello”的地址空间。

当析构的时候,先析构s1,之后再析构s2会发现这块内存已经被释放了,故浅拷贝造成非法的地址访问。

解决方法是自己写拷贝构造和赋值方法。

	String(const String &str)
	{
		data = new char(strlen(str.data) + 1);
		strcpy(data, str.data);
	}
	String& operator=(const String &str)
	{
		if (this != &str)
		{
			delete[]data;
			data = new char(strlen(str.data) + 1);
			strcpy(data, str.data);
		}
		return *this;
	}

自己实现的方法,就是先申请一块内存,进行拷贝,拷贝指针指向的值到新空间。

但是这种深拷贝会造成多块内存存的数据都是一样的,出现浪费内存的现象。

于是使用写时拷贝技术。

写时拷贝技术指的是,当在拷贝构造和赋值的时候,如果对象只是进行读操作,那么采用浅拷贝,多个对象共用一块内存,

当对象需要对内存进行写操作时,立即使用深拷贝,另开辟新内存,拷贝内存上的数据,在新内存上进行写操作。

#include <iostream>
#include <string>
using namespace std;

class String;

class String_rep//全部实现深拷贝   实现一个引用计数器
{
	friend class String;
public:
	String_rep(const char *str=""):count(0)//需要初始化 引用计数器
	{
		if (str == NULL)
		{
			data = new char[1];
			*data = '\0';
		}
		else
		{
			data = new char(strlen(str) + 1);
			strcpy(data, str);
		}
	}
	String_rep(const String_rep &str) :count(0) //需要初始化 引用计数器
	{
		data = new char(strlen(str.data) + 1);
		strcpy(data, str.data);
	}
	String_rep& operator=(const String_rep &str)
	{
		if (this != &str)
		{
			delete[]data;
			data = new char(strlen(str.data) + 1);
			strcpy(data, str.data);
			data[strlen(str.data)] = '\0';
		}
		return *this;
	}
	~String_rep()
	{
      	delete[]data;
    	data = NULL;
	}
public:
	void plus()   
	{
		++count;
	}
	void dec()
	{
		if (--count == 0)  //当引用计数器为0 时,就可以释放空间了
		{
			delete this;//调用析构
		}
	}
	char& write(int n)    //为了重载 []
	{
		if (n > -1 && n < strlen(data))
			return data[n];
	}
private:
	char *data;
	int count;  
};

class String
{
public:
	String(const char *str = "")
	{
		rep = new String_rep(str);  //全部交给引用计数器来做,
		rep->plus();   //在string类中只是维护 引用计数器的个数
	}
	String(const String &str)
	{
		rep = str.rep;   //全部用浅拷贝  
		rep->plus();
	}
	String& operator =(const String &str)
	{
		if (this != &str)
		{
			rep->dec();   //旧的引用计数器减一   
			rep = str.rep;   //浅赋值   指向新的引用计数器
			rep->plus();//已经更改了引用计数器   并加一
		}
		return *this;
	}
	char& operator [](int pos)   //重载[]   此时需要写  需要更改了   使用深拷贝
	{
		if (rep->count > 1)
		{
			String_rep *new_rep = new String_rep(rep->data);    //重开辟一块空间
			rep->dec();//原来的减少
			rep = new_rep;//更改指向   新空间
			rep->plus(); // 新空间的引用计数器增加
		}
		return rep->write(pos);  
	}
	~String()
	{
		rep->dec();  //只负责减少   在上面的类中对减少到0 的空间释放
	}
private:
	String_rep *rep;
};
void main()
{
	String s1("hello");
	String s2 (s1);

	s2[0] = 'H';
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值