c++写时拷贝

c++ 写时拷贝:

当一个拷贝构造一个需要动态开辟内存空间的对象时,用浅拷贝就会出现空间被释放两次的情况,这样显然会出现问题,用深拷贝的话就可以解决此问题,但是每一次不管它用不用都是有空间被申请,这样就很浪费。举个不恰当的例子:

就比如一块蛋糕,你就坐一边看着也不吃就那样放着,来了第二个人的话,同样的蛋糕同样不吃在那看着,就需要重新拿一块,这样两个人,两个蛋糕,大家都不吃在那只是盯着预备着就很浪费啊,所以就想办法让第二个来的人同样盯着第一块蛋糕,如果被吃掉了,那么此时在重新申请一块蛋糕,就不会浪费。这时我们可以用计数的写时拷贝就可以解决这个问题。

写时拷贝原理:
       就是“引用计数”。就是在开辟空间的时候,会多开4个字节用于保存引用计数的值。当第一个类构造时,构造函数会根据传入的参数从堆上分配内存,当有其他类需要这块内存时,这个计数会自动累加。当有类析构时,这个计数会减一,直到最后一个类析构时,此时的计数为1或者0,这时,程序才会真正的free这块从堆上分配的内存。那么我们在什么时候需要写时拷贝呢?当然是被修改就需要啦,就相当于同时盯着的蛋糕被吃了,共享的同一块内存的类内容发生改变时,才会发生写时拷贝,不修改就不会发的。

  以Mstring类为例实现写时拷贝:

 

class Mstring
{
public:
	Mstring(const char *str = NULL)
	{
		if(NULL == str)//空串
		{
			_str = new char[1 + 4];
			getNum() = 1;

			*(getHead()) = 0;
			_len = 0;
			return;
		}
		//不空则开辟空间
		_len = strlen(str);
		_str = new char[_len + 1 + 4];
		getNum() = 1;//只有它一个,计数为1
		strcpy_s(getHead(),_len + 1,str);//相同的拷贝一份
	}
	Mstring(const Mstring &src)
	{
		_str = src._str ;//浅拷贝
		_len = src._len ;

		getNum()++;//拷贝构造 计数++
	}
	Mstring & operator = (const Mstring &src)
	{
		if(&src == this)//预防自赋值
		{
			return *this;
		}

		Delete();//预防内存泄露

		_str = src._str ;//浅拷贝
		_len = src._len ;

		getNum()++;

		return *this;
	}
	char & operator*()
	{
		if(getNum() == 1)
		{
			return *getHead();
		}
		char * tmp = new char[_len + 1 + 4];
		strcpy_s(tmp + 4,_len + 1,getHead());
		getNum()--;

		_str = tmp;//一块新的空间
		getNum() = 1;
		return *getHead();
	}
	char &operator[](int sit)
	{
		if(getNum() == 1)
		{
			return getHead()[sit];
		}
		char * tmp = new char[_len + 1 + 4];
		strcpy_s(tmp + 4,_len + 1,getHead());
		getNum()--;

		_str = tmp;
		getNum() = 1;

		return getHead()[sit];
	}
	ostream & operator<<(ostream & out)
	{
		out<<getNum()<<"   ";
		out<<getHead()<<endl;
		return out;
	}

	~Mstring()
	{
		Delete();
	}
private:
	int &getNum()
	{
		return *((int *)_str);
	}
	char * getHead()
	{
		return _str + 4;//真正的头开始
	}
	void Delete()
	{
		getNum()--;
		if(getNum() == 0)
		{
			delete _str;
		}
	}
	char * _str;
	int _len;
};

 主函数:

int main()
{
	Mstring str1 = "hello";
	str1.operator<<(cout);
	cout<<"*****************"<<endl;
	Mstring str2 = str1;
	str1.operator<<(cout);
	str2.operator<<(cout);
	cout<<"*****************"<<endl;
	Mstring str3;
	str3.operator<<(cout);
}

最终结果如下:

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值