程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> C/C++字符串處理之String - 常字符串

C/C++字符串處理之String - 常字符串

編輯:關於C++

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個函數!

你已經看到,BasicString中大量使用TempString來進行規格定義。這種方式的代碼伸縮性無疑相當好。TempString的構 造每增加一種線性字符串的支持,BasicString的所有相關操作即可立即支持該類型的字符串表示。

為了進一步說明這種 做法的好處,我們再以字符串連接(concat)作為例子進行說明:

template <class AllocT, class _E> // 多個字符串連接。
BasicString<_E> concat(AllocT& alloc, TempString<_E> a1, TempString<_E> a2, ...);

concat並非是BasicString類的成員函數。而是與BasicString有密切關系的全局函數。對於STL string類 ,你通常被推薦用operator+或者string::append函數來進行字符串連接。如:

std::string a = std::string ("Hello") + " " + "world" + "!!!";

而對應地,BasicString並 無operator+或者append,它使用全局的std::concat函數進行字符串連接。如下:

std::String a = std::concat(alloc, "Hello", " ", "world", "!!!");

有意思的 是,這個std::concat不只可以高效地連接任意多的字符串,而且,它還可以連接高效地連接各種線性的字符串表示,包括: char*, std::string, std::vector<char>, std::String, std::StringBuilder等。例如:

std::string hello = "Hello";
std::String space(" ", 1);
std::vector<char> excalmatory_mark(3, '!');
std::String a = std::concat(alloc, hello, space, "world", excalmatory_mark);

這其中的奧秘 ,全在TempString上。關於std::TempString的詳細說明,參見TempString。

源碼

stdext/text/TempString.h:

http://code.google.com/p/winx/source/browse/trunk/stdext/include/stdext/text/TempString.h

stdext/text/BasicString.h:

http://code.google.com/p/winx/source/browse/trunk/stdext/include/stdext/text/BasicString.h

StdExt庫的工程主頁:http://code.google.com/p/stdext/

參考閱讀

String:

http://cpp.winxgui.com/cn:string

TempString:

http://cpp.winxgui.com/cn:tempstring

concat:

http://cpp.winxgui.com/cn:concat

std::string:

http://cpp.winxgui.com/cn:std-string

Footnotes

1. C++的內存分配器(allocator)有點奇怪,雖然處處用到它,但是多數程序員對它很陌生。關於這方面 的話題,參閱《C++內存管理專題》(http://cpp.winxgui.com/cn:memory-management)。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved