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