写时拷贝(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;
}
}
以上是关于写时拷贝(copy on write)的主要内容,如果未能解决你的问题,请参考以下文章