什么是引用计数?
一个在堆上创建的对象,记录有多少个指针指向它。
为什么要设计引用计数,他解决什么问题?
1、new出一个临时对象,使用完了,需要delete。但是拥有权会转移(auto_ptr)或者扩散,因此很难确定delete时机。忘记delete导致资源泄漏,过早delete,导致还在使用的指针出现错误,重复delete导致未定义行为。
2、许多对象拥有相同的值,存储多次是个很愚蠢的事,可以共享。
如何实现:
1、以String为例说明,String s1 = "Hello", String s2 = s1; 可以让s1,s2共享"Hello"。
2、引用计数放在哪里呢?显然不能放在String对象中,因为每个String对象都有这个引用计数,引用计数应该和String指向的Value在一起。
3、在String中建立一个嵌套类StringValue,String中有一个字段 StringValue* pStringValue。为什么StringValue设计成嵌套类,因为StringValue只是嵌套在String中,为了实现String,不会出现在其他地方。与此类似的有,STL中各种容器专属的迭代器。
4、StringValue中有:int refCount,记录引用计数。char* pData:指向char。
5、String的copy构造
1 String::String(const String& rhs)2 :pStringValue(rhs.pStringValue)3 {4 ++(pStringValue->refCount);5 }
6、String的copy赋值
1 String& String::operator =(const String& rhs) 2 { 3 if(pStringValue == rhs.pStringValue) //共享的数据赋值 4 { 5 return *this; 6 } 7 8 if(--pStringValue->refCount == 0) //处理老的内容 9 {10 delete pStringValue;11 }12 13 pStringValue = rhs.pStringValue;14 ++pStringValue->refCount;15 16 return *this;17 }
7、String的析构
1 String::~String()2 {3 if(--pStringValue->refCount == 0)4 {5 delete pStringValue;6 } 7 }
8、Copy-On-Write(写时才复制)
考虑s1,s2指向同一个内容,s1[2] = f; 程序员期望只是修改s1,如何支持?
1 char& operator[](int index) 2 { 3 if(this->pStringValue->refCount > 1) //存在其他人共享 4 { 5 --this->pStringValue->refCount; 6 this->pStringValue = new StringValue(pStringValue->pData); 7 } 8 9 return pStringValue->pData[index];10 }
9、考虑 char* pc = &s1[2]; 然后修改pc,还是会修改s2,怎么办?
增加一个标志位,访问[],设置StringValue不是共享。10、现在假如Person,Book也有这种需求,怎么办?
需要建立PersonValue,BookValue,通过建立基类,复用代码。RCValue为基类,RCValue 的copy构造和copy赋值,不需要做任何事,因为不会对RCValue调用copy构造和copy赋值。而是对String,Person,Book调用copy构造,copy赋值,传递pValue指针。
11、对于String中的pStringValue使用smart point,可以实现自动操作引用计数。