写时拷贝(copy on write)

Posted 两片空白

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了写时拷贝(copy on write)相关的知识,希望对你有一定的参考价值。

        适用于深拷贝提高效率的一种方法。

        例如string类,在拷贝构造时,会要用到深拷贝。如果用浅拷贝,会导致两对象的指针指向同一块空间,导致对象析构时,导致同一块空间释放两次,程序奔溃。深拷贝是在对象再开一块空间,将值拷贝过去,再让新对象的指针指向新开辟的空间。

        深拷贝运用写时拷贝时,不会立马申请空间。它是一开始先让新的对象的指针先同时指向同一块空间。在读的时候或者是写的时候再在堆上申请空间给对象。

        这里引入了一个引用计数:用来记录资源使用者的个数。在构造时,将计数给为1,没增加一个对象指向这块空间计数加1(指向的是同一块空间)。当销毁时计数减1,然后再检查是否需要释放该资源(之前对象都指向的空间),如果计数为1,则可以释放,否则不可以释放。

        当是写时拷贝有一个缺陷,如果用户读对象的值的时候,写时拷贝就失效了,也会直接开辟新空间。    

//构造函数(分存内存)
string::string(const char* tmp)
{
	_Len = strlen(tmp);
	_Ptr = new char[_Len + 1 + 1];
	strcpy(_Ptr, tmp);
	_Ptr[_Len + 1] = 0;  // 设置引用计数  
}

//拷贝构造(共享内存)
string::string(const string& str)
{
	if (*this != str){
		this->_Ptr = str.c_str();   //共享内存
		this->_Len = str.szie();
		this->_Ptr[_Len + 1] ++;  //引用计数加一
	}
}

//写时才拷贝Copy-On-Write
char& string::operator[](unsigned int idx)
{
	if (idx > _Len || _Ptr == 0) {
		static char nullchar = 0;
		return nullchar;
	}

	_Ptr[_Len + 1]--;   //引用计数减一
	char* tmp = new char[_Len + 1 + 1];
	strncpy(tmp, _Ptr, _Len + 1);
	_Ptr = tmp;
	_Ptr[_Len + 1] = 0; // 设置新的共享内存的引用计数

	return _Ptr[idx];
}

//析构函数的一些处理
~string()
{
	_Ptr[_Len + 1]--;   //引用计数减一

	// 引用计数为0时,释放内存 
	if (_Ptr[_Len + 1] == 0) {
		delete[] _Ptr;
	}

}

参考:https://coolshell.cn/articles/12199.html

以上是关于写时拷贝(copy on write)的主要内容,如果未能解决你的问题,请参考以下文章

string类的写时才拷贝(Copy-On-Write)

写时拷贝(copy on write)

Linux写时拷贝技术(copy-on-write)

写时拷贝COW(copy-on-write)

死磕 Java 基础 — 谈谈那个写时拷贝技术(copy-on-write)

死磕 Java 基础 — 谈谈那个写时拷贝技术(copy-on-write)