string 类写到这里已经是升级版了,大家能看懂多少算多少,在面试的时候尽量不要给面试官说你懂这个,万一把自己搞糊涂了,岂不是得不偿失。
好了 ,废话到此结束,正文开始。
string 类写到这里已经是升级版了,大家能看懂多少算多少,在面试的时候尽量不要给面试官说你懂这个,万一把自己搞糊涂了,岂不是得不偿失。
好了 ,废话到此结束,正文开始。
我们知道,在浅拷贝当中,由于多个对象共用同一块空间,最后释放内存的时候导致同一块内存多次释放而出现问题,那么问题来了,**能否保证当多个对象共同使用同一块空间时,该空间只释放一次? **答案当然是可以的了。 引用计数原理:当多个对象共享同一块资源时,要保证该资源只释放一次,只需要记录有多少个对象在管理这份资源即可,每增加(减少)一个对象相时,给该记数加一(减一),当最后一个对象不使用时,该对象负责将资源释放掉即可。 具体操作我们看代码:
class String
{
public:
String(const char* pStr = "")
:_pCount(new char(1))
{
if (NULL == pStr)
{
_pStr = new char[1];
*_pStr = '\0';
}
else
{
_pStr = new char[strlen(pStr) + 1];
strcpy(_pStr, pStr);
}
}
String(const String& s)
:_pStr(s._pStr)
, _pCount(s._pCount) //引用计数
{
++(*_pCount); //有几个对象调用拷贝构造函数就给_pCount++一下,计算具体有几个对象在共同使用这块空间
}
String& operator=(const String& s)
{
if (_pStr != s._pStr)
{
if (_pStr && 0 == (--(*_pCount))) //如果这块空间存在并且只有一个对象在管理这块空间就进行下一步
{
delete[] _pStr;
delete _pCount;
}
_pStr = s._pStr;
_pCount = s._pCount;
++(*_pCount);
}
return *this;
}
~String()
{
if (_pStr && 0 == (--(*_pCount)))
{
delete[] _pStr;
_pStr = NULL;
delete _pCount;
_pCount = NULL;
}
}
private:
char* _pStr;
}
采用引用计数后虽然解决了这个问题,但它仍然是浅拷贝,而且,如果对象很多的话,我们可能会忘记释放某一些空间,为了完美的解决这个小小的缺陷,我们又引进了写时拷贝这个概念。
以前在动态内存开辟中说new[]的时候应该说过new[]在底层其实人家是给它多开辟了4个字节的内存,用来存放引用记数,这样不仅解决了上述问题还可以让我们随意更改单个字符。
public:
String(const char* pStr = "")
{
if (NULL == pStr)
{
_pStr = new char[1+4];
_pStr += 4;
*_pStr = '\0';
}
else
{
_pStr = new char[strlen(pStr) + 1+4];
_pStr += 4;
strcpy(_pStr, pStr);
}
GetRef() = 1; //放引用计数
}
String(const String& s)
:_pStr(s._pStr)
{
GetRef()++;
}
//写时拷贝----COW(Copy On Write)只能用于单线程
String& operator=(const String& s)
{
if (_pStr != s._pStr)
{
Release();
_pStr = s._pStr;
++GetRef();
}
return *this;
}
~String()
{
Release();
}
char& operator[](size_t index)
{
if (GetRef() > 1)
{
char* pTemp = new char[strlen(_pStr) + 1 + 4];
*(int*)pTemp = 1; //放引用计数
pTemp += 4;
strcpy(pTemp , _pStr);
--GetRef();
_pStr = pTemp;
}
return _pStr[index];
}
const char& operator[](size_t index)const
{
return _pStr[index];
}
private:
int& GetRef() //引用计数
{
return *((int*)_pStr - 1);
}
void Release() //释放空间
{
if (_pStr && 0 == --GetRef())
{
_pStr -= 4;
delete[] _pStr;
_pStr = NULL;
}
}
private:
char* _pStr;
};
void TestFunc()
{
String s1("Hello");
String s2(s1);
s2[0] = 'w';
String s3;
s3 = s2;
const String s4("Bit");
s4[1];
}
int main()
{
TestFunc();
return 0;
}
看看效果: