C/C++字串處理(4):std::vector與std::StringBuilder
許式偉
2008-3-28
引子
std::StringBuilder 基於 std::vector 實現。所以儘管本文討論 std::vector,但是所有的結論對 std::StringBuilder 同樣有效。
實現概要
簡單來講,std::vector 是一個動態數組,管理的是一塊線性、可動態增長的記憶體。
如何加速 std::vector?使用 vector::reserve
在大致可預估 vector 大小時,在插入資料前,應該先調用 reserve(size) 進行記憶體的預分配(這裡 size 是預估的vector元素個數)。
避免在vector開始(begin)插入/刪除資料
也就是說,應該盡量用 vector::insert(end(), …) 或者 vector::push_back/pop_back 添加/刪除資料。而不要用 vector::insert(begin(), …) 操作。vector 沒有提供 push_front 操作,原因只有一個:從 vector 開始處插入/刪除資料是低效的做法。
如果你需要大量的在容器開始(begin)處 insert 資料,那麼可以選擇 std::deque(有 vector 隨機訪問的優點,也有 list 高效插入的優點)或者 std::list。
std::vector 的缺陷什麼時候不能用 std::vector ?
在容器需要容納海量資料,並且元素個數不可預知時,堅決不能用 std::vector。所有基於線性記憶體的資料結構(如 std::vector,std::string)在海量資料時,遭遇效能瓶頸。
記憶體片段
基於線性記憶體的資料結構(如 std::vector,std::string),還有一個典型的問題,就是容易產生記憶體片段。在大量操作 std::vector 或 std::string 後,記憶體片段就會比較嚴重。
std::vector 與 allocator
我們知道,std::vector 的原型是:
template <class DataT, class AllocT = std::allocator<DataT> >
class vector;
那麼是否需要像我們針對 Map/MultiMap、Set/MultiSet、List/Slist、HashMap/HashMultiMap、HashSet/HashMultiSet、Deque 做的那樣,將 AllocT 改用 GC Allocator呢?
答案是:不需要。GC Allocator 對於改善小記憶體配置是有益的。但是在動態線性記憶體的資料結構無效。這樣的資料結構除了 std::vector 外,典型的還有 std::string(std::basic_string)。
推薦閱讀
- std::deque - 介於 std::vector 與 std::list 之間的一個資料結構,既可以隨機定位,海量資料是效能仍然非常穩健(事實上其 push_back/push_front 的效能幾乎為常數:O(1),而不像 std::vector 那樣,隨著元素的增加,插入速度急劇下降)。
- std::list - 雙向鏈表。