由於淺拷貝使多個對象共用一塊內存地址,調用析構函數時導致一塊內存被多次釋放,導致程序奔潰。
實現string類的時候通常顯示的定義拷貝構造函數和運算符重載函數。
由於釋放內存空間,開闢內存空間時花費時間,因此,在我們在不需要寫,只是讀的時候就可以不用新開闢內存空間,就用淺拷貝的方式創建對象,當我們需要寫的時候纔去新開闢內存空間。這種方法就是寫時拷貝。
在構造函數中開闢新的空間時多開闢4個字節的空間,用來存放引用計數器,記錄這快空間的引用次數。
#include<iostream> #include<stdlib.h> using namespace std; class String { public: String(char *str = "") :_str(new char[strlen(str) + 5]) { *(int *)_str = 1; _str += 4; strcpy(_str, str); } ~String() { if (_str != NULL) { _Release(); } } String(const String& str) { _str = str._str; ++_GetRefCount(); } String& operator=(const String& str) { if (this != &str) { _Release(); _str = str._str; ++ _GetRefCount(); } return *this; } char& operator[](int index)//寫時拷貝 { if (_GetRefCount()>1)//當引用次數大於1時新開闢內存空間 { --_GetRefCount();//原來得空間引用計數器減1 char *str = new char[strlen(_str) + 5]; strcpy(str+4, _str); _str = str+4; _GetRefCount()++; } return _str[index]; } friend ostream& operator<<(ostream& output, const String& str) { output << str._str; return output; } private: int& _GetRefCount() { return *(int *)(_str - 4); } void _Release() { if (--_GetRefCount() == 0) { delete[] (_str-4); } } private: char *_str; };