Boost C++ Libraries Home Libraries People FAQ More

PrevUpHomeNext

Design Topics(設計話題)

string 表示法
序列特徵
查找算法
替換算法
查找迭代器 & 分割算法
異常安全

string 表示法

顧名思義,本庫主要是和 strings 一起工作的。然而,在本庫的語境中,一個 string 並不局限於任何特定的實現(比如 std::basic_string),而是一個概念。這就允許本庫的算法為任何滿足給定要求的 string 類型所復用。

定義:一個 string 就是一個可以用連續有序方式訪問的 characters 的 range。character 是任何帶有「廉價」拷貝和賦值c 操作的值類型(基於前文所述原因,譯文中的 character 和 string 一律保留原文,而不譯為字符和字符串,只有明確表示為通常意義上的字符或字符串時才譯為中文——譯者)。

string-type 的第一個要求是必須可以用 Boost.Range 訪問。這一便利條件允許以一種統一的基於迭代器的方式訪問 string 中的元素。這對於我們的庫來說已經足夠了。

第二個要求清楚地規定了 characters 存儲在 string 中的方法。本庫中的算法在工作時假設拷貝一個 character 是比較廉價的,並因此分配額外的存儲空間以緩存結果。對於常見的 character 類型來說這是一個正常的假設。即使這個要求沒有被滿足,算法也可以工作,但要付出性能降低的代價。

另外,有些算法對 string-type 有額外的要求。特別是,那些可以創建一個給定類型的新 string 的算法。在這種情況下,它要求這個類型滿足序列 (Std §23.1.1) 要求。

在參考和代碼中,對 string 類型的要求通過模板參數的名字表現出來。RangeT 意味著基本的 range 要求必須有效。SequenceT 表明擴展的序列要求。

序列特徵

std::liststd::vector 的最大不同不在於它們提供的接口,而在於類的內部細節以及它執行各種操作的方法。問題是不依靠任何特殊機制而僅僅通過類的定義不可能推斷出這些不同。但是,有些算法在瞭解了特定容器的性質後運行速度會有大幅度的提升。

序列特徵允許開發者指定一個序列容器的額外性質(參見 Std §23.2)。因此這些性質可以被算法用來為某些操作選擇優化處理。這些序列特性聲明在頭文件 boost/algorithm/string/sequence_traits.hpp 中。

在下表中,C 表示一個容器,而 c 是 C 的一個對象。

Table 17.12. 序列特徵

特徵 說明
has_native_replace<C>::value 表明這個序列具有類似 std::string 的替換方法。
has_stable_iterators<C>::value 表明這個序列具有穩定的迭代器。這也就意味著,像 insert/erase/replace 這樣的操作不會導致迭代器失效。
has_const_time_insert<C>::value 表明序列的 insert 方法具有常量時間複雜度。
has_const_time_erase<C>::value 表明序列的 erase 方法具有常量時間複雜度。

當前實現中包含針對標準庫中的 std::list<T> 和 std::basic_string<T> 以及 SGI 的 std::rope<T> 和 std::slist<T> 的特化。

查找算法

查找算法具有與 std::search() 算法類似的功能。它們提供了一個不同的接口,更適合常用的 string 操作。它們不再僅僅返回匹配子序列的開始位置,而是返回一個 range,這在事先不知道匹配子序列的長度時是非常必要的。這個特性也允許將輸入序列分割為三個部分:一個前綴,一個 substring 和一個後綴。

另一個不同是在 find_first 之外又增加了很多搜索方法,包括 find_regex。

在本庫中,查找算法是實現為 Finders 的。Finders 也被其它部件 (replace, split) 使用。為便於使用,還有函數將這些 Finders 包裝成簡單的查找操作。

當前本庫只包含了複雜度為 O(n * m) 的查找算法的初級實現,這裡的 n 是輸入序列的大小,而 m 是搜索序列的大小。要不是因為對於較小的序列來說,常量成本都是相當大的,算法本來可以帶有 O(n) 複雜度。對於小的 m << n(m 在數量級上比 n 小),當前實現提供了可以接受的性能。即使在 C++ 標準中為查找算法定義的必要複雜度都是 O(n * m)。在庫的未來版本中,可能會包含可選的線性複雜度的算法。

替換算法

替換算法的實現遵循了本庫的分層結構。較低的層次實現了通用的對輸入序列中的一個 range 的置換。這個層次用一個 Finder 對像和一個 Formatter 對像作為輸入。這兩個仿函數規定什麼被替換以及用什麼來替換。Finders 被查找和分割部件共享。

照常,較低層次的實現在盡可能利用特定特性(通過使用序列特性)的情況下,針對通用序列進行設計。

查找迭代器 & 分割算法

查找迭代器是查找部件的合理擴展。它不是僅搜索一個匹配項,而是迭代地搜索整個輸入,以找到多個匹配項。搜索的結果被用來將輸入分割為若幹部分。它們可以是匹配的部分 (find_iterator) 也可以是各匹配項之間部分 (split_iterator)。這取決於返回這些部分作為結果的那個算法。

另外,像 find_all()split() 這樣的分割算法可以簡化常用的操作。它們使用一個查找迭代器去搜索整個輸入並將找到的匹配項拷貝到已提供好的容器中。

異常安全

本庫要求對用作模板或函數參數的所有項目提供 basic exception-safety guarantee(基本異常安全保證)。反過來,本庫中的所有函數和算法,除非另有說明,都將提供 basic exception-safety guarantee(基本異常安全保證)。換句話說:本庫在面對異常時,它將保持它的不變量且不洩漏資源。某些庫操作給出更強的保證,這些都被記錄到個別的文檔中。

某些函數可以提供 strong exception-safety guarantee(強異常安全保證)。這意味著以下描述成立:

  • 如果拋出一個異常,不會對函數以外產生影響
  • 如果一個異常不是由這個函數拋出的,則沒有影響

這種保證在這種條件下才會提供:這個操作所針對的類型用作既提供強異常保證又不改變全局狀態的函數的參數。

在參考中,術語 strong exception-safety guarantee(強異常安全保證),就意味著上面的定義。

關於異常安全話題的更多信息,請參考這個連接

Last revised: February 27, 2008 at 15:00:24 -0500


PrevUpHomeNext