当类里面有指针对象时,采用简单的赋值浅拷贝,使得两个指针指向同一块内存,则析构两次,存在内存奔溃的问题,因此浅拷贝中利用引用计数。

//引用计数浅拷贝

class String
{
public:
 String(char*str = "")
  :_str(new char[strlen(str) + 1])
  , _pRefCount(new int(1))
 {}
 String(const String & s)
  :_str(s._str)
  , _pRefCount(s._pRefCount)
 {
  ++(*_pRefCount);
 }
 String &operator=(const String & s)
 {
  if (this != &s)
  {
   if (--(*_pRefCount) == 0)
   {
    delete[]_str;
    delete _pRefCount;
   }
   _str = s._str;
   _pRefCount = s._pRefCount;
   ++(*_pRefCount);
  }
  return *this;
 }
 ~String()
 {
  if (--(*_pRefCount)==0)
  {
   delete[]_str;
  }
 }
private:
 char*_str;
 int*_pRefCount;
};

同之前的delete[ ] 一样,当我们为string 分配内存时,总是多分配一个空间来存储引用计数。在每个内存块的前四个字节来存放一个整数,而真正的内容则在其后。


//写时拷贝

class String
{
public:
 String(const char*str="")
  :_str(new char[strlen(str)+5])
 {
  cout << "String()" << endl;
  _str += 4;
  _GetRefCount(_str) = 1;
  strcpy(_str, str);
 }
 
 String(const String &s)
  :_str(s._str)
 {
  cout << "String(const String &s)" << endl;
  ++_GetRefCount(_str);
 }
 
 String&operator=(const String &s)
 {
  if (_str!=s._str)
  {
   _Release();
   _str = s._str;
   ++_GetRefCount(_str);
  }
  return *this;
 }
 
 ~String()
 {
  cout << "~String()" << endl;
  _Release();
 }
 
//写时才拷贝,当两个对象共享一块内存时,若其中的一个需要修改内容,则此时谁修改,谁在另外地方申请新的空间,将之前共用内存块的引用计数减一,将内容复制到新的空间,并把引用计数设置为1.
 char&operator[](size_t Index)
 {
  if (_GetRefCount(_str) > 1)
  {
   --(_GetRefCount(_str));
   char*tmp = new char[strlen(_str) + 5];
   tmp += 4;
   _GetRefCount(tmp) = 1;
   strcpy(tmp, _str);
   _str = tmp;
  }
  return _str[Index];
 }

 char* C_Str()
 {
  return _str;
 }
private:

 int& _GetRefCount(char *str)
 {
  return *(int*)(str - 4);
 }
 
 void _Release()
 {
  if (--_GetRefCount(_str) == 0)
  {
   delete[](_str - 4);
  }
 }
 
private:
 char*_str;
};
 
void Test2()
{
 String s1("xello");
 String s2(s1);
 s1[0] = 'h';
 cout << s1.C_Str() << endl;
 cout << s2.C_Str() << endl;
}
 
int main()
{
 Test2();
 system("pause");
 return 0;
}