引子
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(http://cpp.winxgui.com/cn:std-deque) - 介於 std::vector 與 std::list 之間的一個數據結構,既可以隨 機定位,海量數據是性能仍然非常穩健(事實上其 push_back/push_front 的性能幾乎為常數:O(1),而不像 std::vector 那 樣,隨著元素的增加,插入速度急劇下降)。
std::list(http://cpp.winxgui.com/cn:std-list) - 雙向鏈表。