String_(C++标准库)

**<string>**是 C++ 標準程式庫中的一個標頭檔，定義了 C++ 標準中的字串的基本模板類 std::basic\_string 及相關的模板類別實例：

其中的 **string** 是以 char 作為模板參數的模板類別實例，把字串的記憶體管理責任由 `string` 負責而不是由編程者負責，大大減輕了 C 語言風格的字串的麻煩。

`std::basic_string` 提供了大量的字串操作函式，如比較、連接、搜尋、替換、獲得子串等。並可與 C 語言風格字串雙向轉換。`std::basic_string` 屬於 C++ STL 容器類，使用者自訂的類也可以作為它的模板參數，因此也適用 C++ STL Algorithm 庫。

`string` 本質上是以字元作為元素的 vector 特化版本；不存在 0 字元結尾這個概念，能裝入 '\0' 這種資料。

## std::basic\_string 類別模板

`std::basic_string` 類別模板儲存且操縱類似 char 的物件的序列。該物件類型的性質由特性類別模板 std::char\_traits 的實例來提供，並作為 `std::basic_string` 的第二個模板參數。

C++11 標準規定：basic\_string 的元素是**連續**儲存的。即對於 basic\_string s，有：`&*(s.begin() + n) == &*s.begin() + n`，其中 n 屬於 [0, s.size ())。換句話說，指向 s [0] 的指標即為指向 CharT [] 陣列的首元素指標。C++11 已經禁止了寫入時複製（copy-on-write) 的實現，因為存在多執行緒安全問題。一般都採用了小字串最佳化（SSO）實現，如 Visual C++：

GCC 從版本 5 開始，std::string 不再採用 COW 策略。

C++17 標準規定，basic\_string 是 AllocatorAwareContainer, SequenceContainer 與 ContiguousContainer。

### 模板參數

* CharT - 字元類型
* Traits - 字元的特性類
* Allocator 內部儲存的分配器類

### 成員類型

* traits\_type 模板參數 Traits
* value\_type 即 Traits::char\_type
* allocator\_type 模板參數 Allocator
* size\_type 即 Allocator::size\_type。C++11 改為 std::allocator\_traits<Allocator>::size\_type
* difference\_type 即 Allocator::difference\_type。C++11 改為 std::allocator\_traits<Allocator>::difference\_type
* reference 即 Allocator::reference。C++11 改為 value\_type&
* const\_reference 即 Allocator::const\_reference。C++11 改為 const value\_type&
* pointer 即 Allocator::pointer。C++11 改為 std::allocator\_traits<Allocator>::pointer
* const\_pointer 即 Allocator::const\_pointer。C++11 改為 std::allocator\_traits<Allocator>::const\_pointer
* iterator 屬於 RandomAccessIterator
* const\_iterator 屬於 Constant random access iterator
* reverse\_iterator 即 std::reverse\_iterator<iterator>
* const\_reverse\_iterator 即 std::reverse\_iterator<const\_iterator>

### 成員函式

下面列出所有成員函式，其中 `string` 是 `std::basic_string<T>` 的簡寫：

* 構造表示
  * `string::string`（構造）
  * `string::~string`（解構）
  * `string::operator=` - 賦值
  * `string::assign` –賦值
  * `string::get_allocator` –獲得記憶體分配器
* 字元存取
  * `string::at` –存取特定字元，帶邊界檢查
  * `string::operator[]` –存取特定字元
  * `string::front` –存取第一個字元
  * `string::back` –存取最後一個字元
  * `string::data` –存取基礎陣列，C++11 後與 c\_str () 完全相同
  * `string::c_str` –返回對應於字串內容的 C 風格零結尾的唯讀字串
  * `string::substr` –以子串構造一個新串；參數為空時取全部源串
* 迭代器
  * `string::begin` –獲得指向開始位置的迭代器
  * `string::end` –獲得指向末尾的迭代器
  * `string::rbegin` –獲得指向末尾的逆向迭代器
  * `string::rend` –獲得指向開始位置的逆向迭代器
  * `string::cbegin` –獲得指向開始位置的唯讀迭代器
  * `string::cend` –獲得指向末尾的唯讀迭代器
  * `string::crbegin` –獲得指向末尾的逆向唯讀迭代器
  * `string::crend` –獲得指向開始位置的逆向唯讀迭代器
* 容量
  * `string::empty` –檢查是否為空
  * `string::size` –返回資料的字元長度
  * `string::length` –返回資料的字元長度，與 size () 完全相同
  * `string::max_size` –返回可儲存的最大的位元組容量，在 32 位 Windows 上大概為 43 億位元組。
  * `string::reserve` –改變 string 的字元儲存容量，實際獲得的儲存容量不小於 reserve 的參數值。
  * `string::capacity` –返回當前的字元儲存容量
  * `string::shrink_to_fit`（C++11 新增）–降低記憶體容量到剛好
* 修改器
  * `string::clear` –清空內容
  * `string::insert` –插入字元或字串。目標 string 中的插入位置可用整數值或迭代器表示。如果參數僅為一個迭代器，則在其所指位置插入 0 值。
  * `string::erase` –刪除 1 個或 1 段字元
  * `string::push_back` –追加 1 個字元
  * `string::pop_back` –刪除最後 1 個字元，C++11 標準引入
  * `string::append` –追加字元或字串
  * `string::operator+=` –追加，只有一個參數 —— 字元指標、字元或字串；不像 append () 一樣可以追加參數的子串或若干相同字元
  * `string::copy` –拷貝出一段字元到 C 風格字元陣列；有溢位危險
  * `string::resize` –改變（增加或減少）字串長度；如果增加了字串長度，新字元預設為 0 值
  * `string::swap` –與另一個 string 交換內容
  * `string::replace` –替換子串；如果替換源資料與被替換資料的長度不等，則結果字串的長度發生改變
* 搜尋
  * `string::find` –前向搜尋特定子串的第一次出現
  * `string::rfind` –從尾部開始，後向搜尋特定子串的第一次出現
  * `string::find_first_of` –搜尋指定字元集合中任意字元在 \*this 中的第一次出現
  * `string::find_last_of` –搜尋指定字元集合中任意字元在 \*this 中的最後一次出現
  * `string::find_first_not_of` –\*this 中的不屬於指定字元集合的首個字元
  * `string::find_last_not_of` –\*this 中的不屬於指定字元集合的末個字元
  * `string::compare` –與參數字串比較

### 常數值

* * `string::npos` –表示「未找到」，值為 `static const unsigned -1`

### 非成員的有關的全域函式

* * `std::operator+` –字串連接
  * `std::operator!=` –不等比較
  * `std::operator==` –相等比較
  * `std::operator<` –小於比較
  * `std::operator<=` –小於等於比較
  * `std::operator>` –大於比較
  * `std::operator>=` –大於等於比較
  * `std::operator<<` –字串內容寫到輸出流中
  * `std::operator>>` –從輸入流中讀取一個字串
  * `std::getline` –從 istream 中讀入一行或一段字元到 string 中
  * `std::swap` –交換兩個 string 的內容。是 std::swap 演算法針對 std::basic\_string 的特化版本
  * `std::stoi` –字串轉為整形
  * `std::stol` –字串轉為長整形
  * `std::stoll` –字串轉為長長整形
  * `std::stoul` –字串轉為無符號長整形
  * `std::stoull` –字串轉為無符號長長整形
  * `std::stof` –字串轉為單精度浮點形
  * `std::stod` –字串轉為雙精度浮點形
  * `std::stold` –字串轉為長雙精度浮點形
  * `std::to_string` –整型、無符號整型、浮點型轉化為 string
  * `std::to_wstring` –整型、無符號整型、浮點型轉化為 wstring
  * `std::hash<std::string>` –計算 hash 值
  * `std::hash<std::wstring>` –計算 hash 值
  * `std::hash<std::u16string>` –計算 hash 值
  * `std::hash<std::u32string>` –計算 hash 值

### 字面量

C++14 標準定義了如下的 std::basic\_string 字面量：

* string operator "" s（const char \*str, std::size\_t len）;
* u16string operator "" s（const char16\_t \*str, std::size\_t len）;
* u32string operator "" s（const char32\_t \*str, std::size\_t len）;
* wstring operator "" s（const wchar\_t \*str, std::size\_t len）;

範例：

### 構造 hash 值的函式

C++11 標準引入了 4 個 std::hash 函式模板的特化。用於以 string 為鍵值的 hash 定址。

* template<> struct hash<std::string>;
* template<> struct hash<std::wstring>;
* template<> struct hash<std::u16string>;
* template<> struct hash<std::u32string>;

## std::char\_traits 類

char\_traits 是一個 traits 類別模板。用於抽象出給定字元類型的字元特性與字串操作。char\_traits 用於明確（explicit）實例化一個 `std::basic_string` 類別模板。

* 成員類型
  * char\_type CharT
  * int\_type 可以保持 char\_type 以及 EOF 的值的整數類型
  * off\_type 實現定義
  * pos\_type 實現定義
  * state\_type 實現定義
* 成員函式
  * assign [static] 賦值一個字元
  * eq [static] 比較兩個字元相等
  * lt [static] 比較兩個字元小於
  * move [static] 移動一個字元序列到另一個字元序列
  * copy [static] 複製一個字元序列
  * compare [static] 詞典序比較兩個字元序列
  * length [static] 返回一個字元序列的長度
  * find [static] 在一個字元序列中找到一個字元
  * to\_char\_type [static] 轉化整型值到相等的 char\_type
  * to\_int\_type [static] 轉化 char\_type 到相等的整型值
  * eq\_int\_type [static] 比較兩個整型值
  * eof [static] 返回 eof 值
  * not\_eof [static] 檢查一個字元是否為 eof 值

例如，如果需要定義「兩個字元相等」若且唯若「兩個字元的大寫形式相等」，就可以在 std::char\_traits<char> 之上衍生定義一個類，多載定義 eq、lt、compare、find 四個靜態成員函式。再用此特性類作為第二個模板參數去實例化 std::basic\_string 類別模板。

## C++11 放棄了 COW

從 C++11 開始，明確禁止用「寫時複製」（Copy On Write）實現 stl::string。因為這在並行時容易引發錯誤。如下例的注釋：

## 小物件最佳化

現在的主流編譯器與標準庫基本都採用了小物件最佳化（small objects optimization，又叫 small buffer optimization），以節約動態分配記憶體開銷。

* Visual C++：0 至 15 個位元組。在 release 版中，小字串緩衝區和儲存區指標復用為一個 union，再加上資料長度、資料區總長度，共計 24 個位元組（32 位元非寬字元）或 32 個位元組（64 位元非寬字元）；在 debug 中，小字串緩衝區和儲存區指標各有自己的儲存空間，因為共計 28 個位元組（32 位元非寬字元）或 40 個位元組（64 位元非寬字元）。
* GCC >= 5：0 至 15 個位元組
* clang:：0 至 22 個位元組

## 用法

由於字串的拷貝操作與其位元組長度成比例，是 _O_（_n_）量級。且建立字串的臨時棧物件的成本開銷。因此 `string` 一般作為常數參照（reference-to-const）以避免不必要的拷貝：

`c_str()` 成員函式返回 string 類的 C 語言風格字串（即 ASCII - 零串）的指標，用於 C 語言字串的互操作。如果不需要零結尾的字串，那麼成員函式 `data()` 返回不一定是 0 結尾的字串的記憶體位址。

## 參考文獻