引用计数的写时拷贝
来源:互联网 发布:如何注册淘宝商标 编辑:程序博客网 时间:2024/05/22 01:28
什么是写时拷贝
首先我们需要知道什么是写时拷贝,写时拷贝,通俗点说也就是写的时候拷贝。那么什么是写的时候拷贝呢,这又是什么意思呢?
举个例子,创建一个日期类的对象,然后又用这个对象拷贝构造了多个堆想,也就是说这几个对象所指向的是同一块空间,那么当你对其中一个对象进行读操作的时候,什么问题都不会有,那么当你对某个对象进行写操作的时候,问题就出现了,一个对象的改变会影响其他对象,但是这并不是我们想要的,虽然说共用同一块空间,但是对象是独立的。我的改变应该不会影响别人。那么为了解决这个问题,我们就引入了写时拷贝这个概念,就是说,当你要对某个对象进行写才做,而这个对象又与其他对象共用同一块空间,此时,就需要,再重新开一段空间,吧你要进行写操作的那个对象拷贝过来,然后再进行写操作,这样就不会影响其他的对象了。
下面一段代码来解释一下
#include<iostream>using namespace std; class String { private: char* _str; public: String(char* str = "") :_str(new char [strlen(str)+1]) { strcpy(_str,str); cout<<"String(char*)"<<endl; } String(const String&str) :_str(str._str) { cout<<"String(const &)"<<endl; } ~String() { if(_str!=NULL) delete []_str; _str = NULL; cout<<"~String"<<endl; } }; int main(){ String s1("qwer"); String s2(s1); String s3(s2); return 0;}
运行结果如下图
图中我们可以看到,三个对象的地址是相同的,也就是是,指向同一块空间,但是按照常规的特点,三个对象应该是要析构三次,但是在这里,因为是只有一块空间,析构一次后,在慈溪构系统就崩溃了。为了解决这个问题我们引入了引用计数,就是可以定义一个变量用来宝存,一块空间对象的个数,当要进行写操作的时候就按照上面所说的方法,先拷贝再写,但是需要改变引用计数。这样就可以实现写时拷贝了。
写时拷贝的代码(引用计数)
class String{private: char *_str; int *_refCountPtr; int _capacity; int _size;public: String(char *str = "") :_refCountPtr(new int(1)) { _capacity = strlen(str); _size = _capacity; _str = new char[_capacity+1]; strcpy(_str,str); cout<<"String(char *str = "")"<<endl; } String(String&s) :_str(s._str) ,_capacity(0) ,_size(0) { _refCountPtr = s._refCountPtr;//改变引用计数 (*_refCountPtr)++; cout<<"String(String&s)"<<endl; } String &operator = (String&s) { cout<<"operator="<<endl; if(_str!=s._str)//自己给自己赋值 { if((*_refCountPtr)==1) { delete[]_str; delete _refCountPtr; } _str = s._str; _refCountPtr = s._refCountPtr; (*_refCountPtr)++; } return *this; } ~String() { Release(); cout<<"~String()"<<endl; }};
还有另外一种方法来实现写时拷贝,具体思想就是,在构造对象的时候就为多开辟四个字节用来存医用技术,这样就不需要变量了,要用引用计数的的时候只需要把它取出来就可以了。
写时拷贝(指针)
class String{private: char* _pStr;public: String(const char* pStr = "") { if(NULL == pStr)//传了一个空字符串 { _pStr = new char[1 + 4];//用了一个指针,多四个字节 _pStr = (char*)(((int*)_pStr)+1);//向后走四个字节 *_pStr = '\0'; } else { _pStr = new char[strlen(pStr) + 1 + 4]; _pStr = (char*)(((int*)_pStr)+1); strcpy(_pStr, pStr); } *((int*)_pStr - 1) = 1;//引用计数初始化为1 } String(const String&s)//直接拷贝,让引用计数加加就好,后面的事析构会做 :_pStr(s._pStr) { ++GetCount(); } String& operator=(const String& s) { if(this != &s)//判断是否自己给自己赋值 { Release();//因为这里要析构,一般我们不会显示的调用析构,所以封装一个函数来代替 _pStr = s._pStr; ++GetCount(); } return *this; } ~String() { Release(); }private: int& GetCount()const { return *((int*)_pStr - 1);//把引用计数取出来 } void Release() { if(_pStr && (0 ==GetCount()--)) { _pStr = (char*)((int*)_pStr-1); delete[] _pStr; _pStr = NULL; } }};
上面这两种方法都可以实现写时拷贝。
阅读全文
1 0
- 引用计数的写时拷贝
- 引用计数的写时拷贝
- String-引用计数的写时拷贝
- 引用计数的写时拷贝
- string引用计数的写时拷贝
- 引用计数+写时拷贝
- 引用计数写时拷贝
- 引用计数写时拷贝
- 引用计数写时拷贝
- 引用计数+写时拷贝
- 引用计数--写时拷贝
- 深浅拷贝&引用计数写时拷贝
- PHP中引用的详解(引用计数、写时拷贝)
- PHP中引用的详解(引用计数、写时拷贝)
- PHP中引用的详解(引用计数、写时拷贝)
- PHP中引用的详解(引用计数、写时拷贝)
- PHP中引用的详解(引用计数、写时拷贝)
- C++::浅拷贝,深拷贝,引用计数的拷贝,写时拷贝
- “玲珑杯”ACM比赛 Round #18 A -- 图论你先敲完模板(DP+思路)
- Kafka源码中的Producer Record定义
- 修改Android Studio缓存log的最大保存数目
- 【实践】Method Tracking
- CRC校验
- 引用计数的写时拷贝
- swift3.0 让方法参数可修改方法
- 任务扫描的架构设计
- iOS所有框架-Cocoatouch等
- mybatis 报字符不能转整型
- Abstract 抽象
- Tensorflow中前向传播算法
- 2762
- Android开机log分析