写时拷贝小结

要想深刻了解写时拷贝,首先得先知道写时拷贝解决了什么问题,所以我们先来谈谈浅拷贝和深拷贝:
浅拷贝就是让当前的指针指向一块已存在的内存区域,和其它指针共享同一块地址空间。浅拷贝带来的问题是当程序结束时,对象d1和d2都会去调用析构函数去清空这块空间,而一块空间析构两次就会导致程序奔溃。
而深拷贝可以在每一次拷贝时为当前指针重新分配空间,不用再去共享那块空间。虽说深拷贝可以很好的解决这个问题,但它也存在自身的问题。比如相同的数据内容如果每次都重新分配空间去放置数据的话,就会造成空间的浪费。为了克服能同时解决这两个问题,就引出了写时拷贝,写时拷贝在浅拷贝的基础上加入了引用计数,当拷贝构造的时候只把引用计数加1,并不重新开辟这块空间,析构的时候只需把引用计数减1,当引用计数为1时才真正析构这块空间。

部分参考:http://blog.csdn.net/zhang1308299607/article/details/74933134

#define _CRT_SECURE_NO_WARNINGS//屏蔽错误
#include
using namespace std;

class Out_of_range
{
};
class String
{
	struct StrNode
	{
		int ref; //对象引用的个数
		int len;//当前字符串的长度
		int size;//总的空间大小
		char data[];//存放的数据
	};
private:
	StrNode* ptr;
public:
	String() :ptr(NULL) {}
	String(const char* p) :ptr(NULL)//此处是首次初始化有参对象时调用的
	{
		cout << "String(const char*p)" << endl;
		if (p != NULL)
		{
			int n = (strlen(p) + 1);
			ptr = (StrNode*)malloc(sizeof(StrNode) + sizeof(char) * n * 2);
			if (NULL == ptr) exit(1);
			ptr->ref = 1;
			ptr->len = n - 1;
			ptr->size = n * 2;
			strcpy(ptr->data, p);
		}
	}
	String(const String& _X) :ptr(NULL)
	{
		cout << "String(const String& _X)" << endl;
		if (_X.ptr != NULL)
		{
			ptr = _X.ptr;
			ptr->ref += 1;
		}
	}
	String& operator=(const String& _X)
	{
		if (this == &_X || this->ptr == _X.ptr) 
		return *this;
	}
	// s1.ptr != NULL  = s2.ptr != NULL;
	   // NULL != NULL
		//!= NULL		     NULL;
		//! 
	const char& operator[](const int index) const
	{
		if (ptr == NULL || index < 0 || index > ptr->len)
		{
			throw Out_of_range();
		}
		return ptr->data[index];
	}
	char& operator[](const int index)//此处分配空间是共享空间中有对象想改变数据时调用的
	{
		if (ptr == NULL || index < 0 || index > ptr->len)
		{
			throw Out_of_range();
		}
		if (ptr->ref > 1)
		{
			size_t size = sizeof(StrNode) + sizeof(char) * ptr->size;
			StrNode* newdata = (StrNode*)malloc(size);
			if (NULL == newdata) exit(1);
			memmove(newdata, ptr, size);
			ptr->ref -= 1;
			ptr = newdata;
			ptr->ref = 1;
		}
		return ptr->data[index];
	}
	~String()
	{
		if (ptr != NULL)
		{
			if (--ptr->ref == 0)
			{
				free(ptr);
			}
		}
		ptr = NULL;
	}
	friend ostream &operator<< (ostream & out, const String & s);
};
ostream& operator<< (ostream& out, const String& s)
{
	for (int i = 0; i <s.ptr->len; i++)
	{
		out << s.ptr->data[i] << " ";
	}
	return out;
}
int main()
{
	String s1("zjhinghello");
	String s2(s1);
	String s3("hello");
	cout << "s1: " << s1 << endl;
	cout << "s2: " << s2 << endl;
	cout << "s3: " << s3 << endl;
	s2[3] = 'z';
	cout << "s2: " << s2 << endl;
	cout << "s1: " << s1 << endl;
	s3 = s2;
	cout << "s2: " << s2 << endl;
	cout << "s3: " << s3 << endl;
	return 0;
}

执行结果:
写时拷贝小结_第1张图片

图解步骤:
写时拷贝小结_第2张图片
写时拷贝小结_第3张图片
写时拷贝小结_第4张图片
写时拷贝小结_第5张图片
解释:共享同一块内存空间的对象,无论其中哪一个对象想改变这块空间的数据,都不能直接进行修改,而是重新开辟一块与原空间等大的空间,把原数据拷贝过去之后,对新空间里的数据进行操作,而重新开辟空间意味着不再引用原空间,从而原空间的引用计数减1。对新开辟的空间引用计数初始化为1,以备后边被引用。

你可能感兴趣的:(笔记,c++,1024程序员节,开发语言)