深入探究C++ string的內部究竟是什麼樣的
在C語言中,有兩種方式表示字串:
- 一種是用字元陣列來容納字串,例如char str[10] = "abc",這樣的字串是可讀寫的;
- 一種是使用字串常量,例如char *str = "abc",這樣的字串只能讀,不能寫。
兩種形式總是以\0作為結束標誌。
C++ string 與它們在C語言中的前身截然不同。首先,也是最重要的不同點,C++ string 隱藏了它所包含的字元序列的物理表示。程式設計人員不必關心陣列的維數或\0方面的問題。
string 在內部封裝了與記憶體和容量有關的資訊。具體地說,C++ string 物件知道自己在記憶體中的開始位置、包含的字元序列以及字元序列長度;當記憶體空間不足時,string 還會自動調整,讓記憶體空間增長到足以容納下所有字元序列的大小。
C++ string 的這種做法,極大地減少了C語言程式設計中三種最常見且最具破壞性的錯誤:
- 陣列越界;
- 通過未被初始化或者被賦以錯誤值的指標來訪問陣列元紊;
- 釋放了陣列所佔記憶體,但是仍然保留了“懸空”指標。
C++ 標準沒有定義 string 類的記憶體佈局,各個編譯器廠商可以提供不同的實現,但必須保證 string 的行為一致。採用這種做法是為了獲得足夠的靈活性。
特別是,C++ 標準沒有定義在哪種確切的情況下應該為 string 物件分配記憶體空間來儲存字元序列。string 記憶體分配規則明確規定:允許但不要求以引用計數(reference counting)的方式實現。但無論是否採用引用計數,其語義都必須一致。
C++ 的這種做法和C語言不同,在C語言中,每個字元型陣列都佔據各自的物理儲存區。在 C++ 中,獨立的幾個 string 物件可以佔據也可以不佔據各自特定的物理儲存區,但是,如果採用引用計數避免了儲存同一資料的拷貝副本,那麼各個獨立的物件(在處理上)必須看起來並表現得就像獨佔地擁有各自的儲存區一樣。例如:
// #include<bits/stdc++.h> #include <iostream> #include <string> using namespace std; int main() { string s1("12345"); string s2 = s1; cout << (s1 == s2) << endl; s1[0] = '6'; cout << "s1 = " << s1 << endl; // 62345 cout << "s2 = " << s2 << endl; // 12345 cout << (s1 == s2) << endl; return 0; }
在 GCC 下的執行結果:
1
s1 = 62345
s2 = 12345
0
只有當字串被修改的時候才建立各自的拷貝,這種實現方式稱為寫時複製(copy-on-write)策略。當字串只是作為值引數(value parameter)或在其他只讀情形下使用,這種方法能夠節省時間和空間。
不論一個庫的實現是不是採用引用計數,它對 string 類的使用者來說都應該是透明的。遺憾的是,情況並不總是這樣。在多執行緒程式中,幾乎不可能安全地使用引用計數來實現。
到此這篇關於C++ string的內部究竟是什麼樣的的文章就介紹到這了,更多相關C++ string內部是什麼內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!