more effective c++——Item M29 引用计数(一)简略的rfstring类设计和写时拷贝
这篇博客中所实现的引用计数还存在未解决的问题——如何通过相同的值多次构造rfstring对象时,防止多次在堆上分配内存?
可以通过在rfstring类中添加一个static list
// static_rfstring.h
#pragma once
#include <list>
using namespace std;
class static_rfstring
{
public:
static_rfstring(const char *str);
static_rfstring(const static_rfstring & rhl);
static_rfstring & operator=(const char *str);
static_rfstring & operator=(const static_rfstring & rhl);
~static_rfstring();
private:
class stringvalue
{
public:
stringvalue(const char *str);
~stringvalue();
char *value;
int rfcount;
};
stringvalue *strvalue;
static list<stringvalue *> strvaluelist;
};
// static_rfstring.cpp
#include "static_rfstring.h"
std::list<static_rfstring::stringvalue *> static_rfstring::strvaluelist;
static_rfstring::static_rfstring(const char *str)
{
// 查找字符串是否已经存在
for (std::list<static_rfstring::stringvalue *>::iterator it = strvaluelist.begin();it != strvaluelist.end();++it)
{
if ((strlen((*it)->value) == strlen(str)) && (0 == strcmp(str, (*it)->value)))
{
(*it)->rfcount++;
strvalue = *it;
return;
}
}
// 不存在则新构建个stringvalue对象
strvalue = new stringvalue(str);
strvaluelist.push_back(strvalue);
}
static_rfstring::static_rfstring(const static_rfstring & rhl)
{
strvalue = rhl.strvalue;
strvalue->rfcount++;
}
static_rfstring & static_rfstring::operator=(const char *str)
{
if (--strvalue->rfcount == 0)
{
delete strvalue;
}
for (std::list<static_rfstring::stringvalue *>::iterator it = strvaluelist.begin(); it != strvaluelist.end(); ++it)
{
if ((strlen((*it)->value) == strlen(str)) && (0 == strcmp(str, (*it)->value)))
{
(*it)->rfcount++;
strvalue = *it;
return *this;
}
}
// 新构建一个stringvalue对象
strvalue = new stringvalue(str);
strvaluelist.push_back(strvalue);
return *this;
}
static_rfstring & static_rfstring::operator=(const static_rfstring & rhl)
{
if (this == &rhl)
{
return *this;
}
if (--strvalue->rfcount == 0)
{
delete strvalue;
}
strvalue = rhl.strvalue;
strvalue->rfcount++;
return *this;
}
static_rfstring::~static_rfstring()
{
for (std::list<static_rfstring::stringvalue *>::iterator it = strvaluelist.begin(); it != strvaluelist.end(); ++it)
{
if ((*it) == strvalue)
{
if (--(*it)->rfcount == 0)
{
strvaluelist.remove(strvalue);
delete strvalue;
}
return;
}
}
}
static_rfstring::stringvalue::stringvalue(const char *str):rfcount(1)
{
value = new char[strlen(str) + 1];
strcpy(value, str);
}
static_rfstring::stringvalue::~stringvalue()
{
delete value;
value = nullptr;
}