原帖:http://www.cnblogs.com/chain2012/archive/2010/11/12/1875578.html
因为Windows的内核对象也运用了引用计数,所以稍作了解并非无用。
引用计数可以让多个对象共享一个数据,而且免除了跟踪控制权的负担,让对象自己管理自己,当再没有被使用时可以自动删除,也算是一种简易的垃圾回收机制。
另一方面,如果有N多个相同的对象:○=○=○=○=...=○=○ 这样的做法是臃肿且无聊的,所以一个好的做法就是让对象可以共享这一个数据。既可以节省内存,又可以提高效率让程序负担更少,不用构造和析构这个值对象的拷贝了。
1 String a, b, c, d, e;
2 a=b=c=d=e="hello";
1 String& String::operator=(const String &rhs)
2 {
3 if (data==&rhs) return *this; //防止自我赋值
4 delete [] data;
5 data = new char[strlen(rhs.data)+1)];
6 strcpy(data, rhs.data);
7 return *this;
8 }
用图显示的话,即:
当a被赋予了另外的值,a="world"; 这时候不能删除这个Hello,应外仍然存在bcde,4个对象在共享这个数据;另外,当只有1个对象x在用这个Hello,而x已经超过了其生存期,没有其他对象指向这个Hello的时候,我们需要删除这个Hello确保不发生资源泄漏。这也就意味着引入引用计数后,图将改变成这样:
- 实现引用计数
应该是每一个String值对应一个计数数值,而不是String对象对应一个引用计数。接下来,新建一个嵌套类StringValue来保存计数和其跟踪的值。
1 #include <string>
2
3 class String {
4 public:
5 String(const char *initValue="");
6 String& String::operator=(const String &rhs);
7
8 private:
9 // StringValue的主要目的是提供一个空间将一个特别的值和共
10 // 享此值的对象的数目联系起来
11 struct StringValue //嵌套类,引用计数
12 {
13 int refCount; //计数数值
14 char *data;
15 StringValue (const char* initValue);
16 ~StringValue();
17 };
18 StringValue *value;
19 };
1 #include "String.h"
2
3 String::StringValue::StringValue(const char* initValue)
4 :refCount(1)
5 {
6 data = new char[strlen(initValue)+1];
7 strcpy(data, initValue);
8 }
9
10 String::StringValue::~StringValue()
11 {
12 delete [] data;
13 }
14
15 String::String(const char *initValue)
16 :value(new StringValue(initValue))
17 {
18
19 }
而这样做通常会产生一个问题,
String s1("More Effective C++");
String s2("More Effective C++");
将会变成这样的数据结构:
想办法改进一下:
1 list<string> String::StringValue::independObj; //独立对象
2 String::StringValue::StringValue(const char* initValue)
3 :refCount(1)
4 {
5 typedef list<string>::iterator lsp;
6 lsp p = find(independObj.begin(), independObj.end(), string(initValue));
7 if (p==independObj.end()||independObj.empty())
8 {//未找到对象,新建
9 data = new char[strlen(initValue)+1];
10 strcpy(data, initValue);
11 independObj.push_back(string(data));
12 }
13 else
14 {
15 // do something...
16 }
17 }
接下来看下String类的拷贝构造函数
String::String(const String& rhs)
: value(rhs.value)
{
++value->refCount;
}
当这样构造2个对象:
String s1("More Effective C++");
String s2(s1);
就会产生这样的数据结构,其代价是非常低廉的,省去了新对象的构造(不必分配新内存和把内容拷贝到这块内存中)和之后的析构(不必释放那块内存),仅仅是使计数+1和拷贝了下指针
拷贝构造函数之后看下析构函数
String::~String()
{
if (--value->refCount == 0)
{
delete value;
}
}
即,当被引用的对象还有其他共享对象时,仅把计数-1;而当没有其他共享对象时,才彻底将引用对象析构掉。接着,是重载赋值操作符,稍微有些复杂
String& String::operator=(const String &rhs)
{
if (value == rhs.value) //赋值的是其本身
return *this; //什么也不做
if (--value->refCount == 0) //如果只有当前对象在共享那个数据
delete value; //则删除掉,因为即将被赋予新的引用。不是的话,仅将计数-1
value = rhs.value; //赋值操作
++value->refCount; //计数器+1
return *this;
}