简洁版:
class String
{
public:
String(char* pStr="")
{
if(pStr==NULL)
{
_pStr=new char[0];
_pStr='\0';
}
else
{
_pStr=new char[strlen(pStr)+1];
strcpy(_pStr,pStr);
}
}
String(const String& s)
{
String str(s._pStr);
_pStr=NULL;
std::swap(_pStr,str._pStr);
}
String& operator=(const String& s)
{
String str(s._pStr);
std::swap(_pStr,str._pStr);
return *this;
}
~String()
{
delete[] _pStr;
_pStr=NULL;
}
private:
char* _pStr;
};
引用计数版
思路:成员变量除了_pStr,再引入一个计数_pCount的。调用构造函数时,将分配的内存标记为1,(表明有1人在使用)。
相应地,调用拷贝构造函数,赋值操作时,每调用一次,_pCount+1,表明使用这段空间的人又多了一个。
同理,在析构函数中,每调用一次,_pCount-1,直到无人使用时,方可删除。
对象模型如下图
class String
{
public:
String(char* pStr=""):_pCount(new int(1))//调用一次构造函数,引用计数加1
{
if(pStr==NULL)
{
_pStr=new char[0];
_pStr='\0';
}
else
{
_pStr=new char[strlen(pStr)+1];
strcpy(_pStr,pStr);
}
}
String(const String& s):_pStr(s._pStr),_pCount(s._pCount)//每调用一次拷贝构造函数,引用计数加1
{
++(*_pCount);
}
String& operator=(const String& s)
{
if(this!=&s)
{
if(0==--(*_pCount))//只有一个人用的话,删除这段空间
{
delete[] _pStr;
_pStr=NULL;
delete _pCount;
_pCount=NULL;
}
_pStr=s._pStr;
_pCount=s._pCount;
++(*_pCount);//引用计数加1
}
return *this;
}
~String()
{
if(0==--(*_pCount) && _pCount)//引用计数为1时,方可删除这段空间
{
delete[] _pStr;
_pStr=NULL;
delete _pCount;
_pCount=NULL;
}
}
private:
char* _pStr;
int* _pCount;
};
写时拷贝
思路:成员变量依旧只有一个char* _pStr,但是用_pStr指向空间的前四个字节来存放同时使用该空间的个数。
所以,调用构造函数时,开辟的空间要多4字节,_pStr需要向后+4,再存放内容,要向前四字节内放入1,表示此时该空间有一人使用。
调用拷贝构造函数和赋值操作时,原理同上面的引用计数相同,需要增加前四字节的值。
调用析构函数时,注意“引用计数”(即前四字节的数)为空时,方可删除,此时,删除前,要将_pStr-4,即将刚多申请的四字节内存一并删去。
对象模型如下图:
class String
{
public:
String(char* pStr="")
{
if(pStr==NULL)
{
_pStr=new char[1+4];
_pStr+=4;
*_pStr='\0';
}
else
{
_pStr=new char[strlen(pStr)+1+4];//多申请4字节
_pStr+=4;//往后移动4字节
strcpy(_pStr,pStr);//拷贝内容
}
GetCount()=1;//计数为1
}
String(const String& s):_pStr(s._pStr)
{
++GetCount();//每次调用计数+1
}
String& operator=(const String& s)
{
Release();//释放原来的空间
_pStr=s._pStr;
++GetCount();//每次调用计数+1
return *this;
}
~String()
{
Release();
}
char& operator[](size_t index)
{
if(GetCount()>1)//当该空间和别人公用时
{
char* temp=new char[strlen(_pStr)+1+4];//重新开辟空间
temp+=4;
strcpy(temp,_pStr);
--GetCount();//原来的计数减1
_pStr=temp;
GetCount()=1;//重新开辟的空间计数为1
}
return _pStr[index];
}
int& GetCount()//获取计数器次数
{
return *((int*)_pStr-1);//将_pStr转为int*,再减1,表明向前移动了4字节。
}
void Release()//释放空间
{
if(0==--GetCount())//只用1人使用时,可以删除
{
_pStr-=4;//指针向前移4字节(删除计数的4字节)
delete[] _pStr;
_pStr=NULL;
}
}
private:
char* _pStr;
};