Table of Contents
概要
理解String(BasicString)
關於TempString基類
源碼
參考閱 讀
概要
我們知道,C++標準庫(STL)提供了string(basic_string)類進行字串操作。字串很可能除了記憶體 分配器(allocator)1外使用最為頻繁的STL類。但是C++社區對string的指責從來就沒有停止過。
歸納起來,STL的 string類主要有以下這些爭議點:
介面過多且規格和其他STL容器沒有達成很好的一致性。例如,string::find使用下標 ,而不是以iterator作為迭代位置,這和其他容器不太一樣。
記憶體片段。由於過於頻繁的字串構造、析構,導致系統 的記憶體片段現象嚴重。
Copy -On-Write與多安全執行緒。string(basic_string)基於Copy-On-Write技術的原因,是因為 string的賦值被設計成為低開銷的。但是一旦考慮到多安全執行緒問題,Copy-On-Write會把大量的時間花在鎖的開銷上。一些新 的STL實現 (如SGI STL)放棄了基於Copy-On-Write的string實現。
我認同這些指責。字串最好的設計,還是將 string分拆為一個常字串(std::String)和一個字串操作類(StringBuilder)。我們的StdExt庫這樣做了。
理解 String(BasicString)
StdExt的String(BasicString),和你以前見過的所有字串類都不太一樣。這個類比你想象 的還要簡單,它只有兩個成員變數:
template <class _E>
class BasicString
{
const _E* m_pszBuf;
size_t m_length;
};
它區別於string(basic_string)之處在於:
它是一個常字串,它永遠不會試圖去篡改字串內容 (m_pszBuf指向的資料)。
它沒有析構,你可以認為其實只是一個結構體。當然,為了方便,BasicString還是有構造函 數。
它的m_pszBuf不以nil為結束。而是由m_length成員限定字串的長度。
它不維護字串內容(m_pszBuf) 的生命週期。如上所述,它沒有析構,任何時刻它只是接受或者產生字串內容,但是不負責銷毀它。
最後一點非常重 要,也是它的特別之處:它並不維護字串的生命週期。這可能讓你詫異:居然會有這樣字串類,它並不管理字串的生命周 期。
但是我們這樣做了。而這的確給我們帶來很多便利。例如:
賦值(複製)、子串(substr)是非常輕量的操 作。Copy-On-Write技術完全是多餘的。
可以將任意的線性容器(如std::vector、std::basic_string)臨時轉換為 String(非常輕量)。參見下文中對String::cast方法的介紹。
為什麼String類可以不管理自己的生命週期?這就是我 們StdExt的記憶體管理變革倡導的思想了。
瀏覽下String類的參考手冊,你注意到有這樣兩個建構函式:
BasicString(const value_type* pszVal, size_type cch);
template <class AllocT>
BasicString(AllocT& alloc, const value_type* pszVal, size_type cch);
這表示:第一個建構函式傳入 的pszVal,其生命週期比BasicString長(到BasicString析構時仍然有效)。而第二個建構函式的意思是,pszVal是一個臨時有 效的字串,這個建構函式將拷貝一個pszVal字串的副本。
為什麼不支援 BasicString(const value_type* pszVal) 這樣的構造?
很簡單,這個構造過於危險,我不能確定你的意圖是什麼。
關於TempString基類
從字面意 思來講,這是一個臨時字串類。為什麼它會是String(即BasicString)的基類?這其實只是實現上的需要。TempString理論 上就是String(只是有特殊的生命週期),和BasicString規格一致。之所以它最後成為BasicString的基類,完全是實現上方便 的考慮。
以BasicString::compare為例,我們考察以下這個函數:
int BasicString::compare(const TempString<_E> b) const;
這個函數的含義非常豐富。相當於定義了以下這一系列的函數:
int BasicString::compare(const _E& b) const; // 與包含單個字元b的字串比較
int BasicString::compare(const _E* b) const; // 與C Style風格的字串b比較
int BasicString::compare(const basic_string<_E>& b) const; // 與STL string比較
int BasicString::compare(const BasicString<_E>& b) const; // 與另一個常String比較
int BasicString::compare(const vector<_E>& b) const; // 與向量表示的字串b比較
int BasicString::compare(const BasicStringBuilder<_E>& b) const;
一個函數可抵6個函數!