简洁版:
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; };