您好,登錄后才能下訂單哦!
String的實現需要注意的是String的拷貝構造。它的拷貝構造有深拷貝和淺拷貝之分。
我們先來用淺拷貝實現String
class String { public: String() { str = new char('A'); } String(char *s) { str = new char[strlen(s) + 1]; if (str != NULL) { strcpy(str, s); } } String(const String& s) { str=s.str; } String& operator=(const String& s) { if (this != &s) { str=s.str; } return *this; } private: char *str; }; void test() { String s1("hello world"); String s2(s1); }
當s1,s2出自的作用域時,會自動調用析構函數,此時s1,s2指向同一片內存。所以這塊內存會被釋放兩次,程序會崩潰。
所以在這里我們要采用深拷貝的方式
構造函數和賦值運算符重載
String(const String& s) { str = new char[strlen(s.str) + 1]; //new出來一塊新的空間 if (str) { strcpy(str, s.str); } } String& operator=(const String& s) { if (this != &s) { if (str != NULL) { delete[] str; str = new char[strlen(s.str) + 1]; strcpy(str, s.str); } } return *this; }
還有一種方法可以解決這個一塊空間會被多次釋放的問題,那就是寫時拷貝
在第一次構造一個對象的時候,多開辟四個字節當做計數器,用來記錄有幾個指針指向這塊空間。每當用這塊空間拷貝構造一個新對象或者把這塊空間賦給另外一個對象時,計數器相應增加。那么當調用析構函數時,每次計數器減一,當計數器減到一時,說明只有一個指針指向這塊空間,此時再把這塊空間delete,就不會出現一塊空間多次釋放的問題了。
class String { public: String(char *str="") :_str(new char[strlen(str)+1+4]) { *((int *)_str) = 1; //將開辟的空間前4個字節強制轉換成整型并賦為1 _str = _str + 4; //將_str重新定為真正字符串開始的地方,這樣比較方便 strcpy(_str, str); //不用每次向后找 } String(const String& str) { _str = str._str; (*((int *)(_str - 4)))++; } ~String() { if (*_str != NULL) { if (((*((int *)(_str - 4)))--) == 0) //判斷計數器是否減到0 { delete[] (_str-4); } } } public: String& operator=(const String& str) { if (this != &str) { if (((*((int *)(_str - 4)))--) == 0) { delete[] (_str-4); } _str = str._str; (*(int *)(str._str - 4))++; return *this; } } char& operator[](int index) { char *tmp = _str; if (((*(int *)(_str - 4))-1) != 0) { (*(int *)(_str - 4))--; _str = new char[strlen(_str) + 5]; (*(int *)(_str + 4)) = 1; _str = _str - 4; strcpy(_str, tmp); } return _str[index]; } private: char *_str; };
但是這樣做也有一個壞處。就是指向同一塊空間的指針,只要改一個指針指向的內容,等于其他的指針指向的內容也跟著改變了。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。