C++標準容器

C++ 裏的容器很多,但可以按照不同的標準進行分類,常見的一種分類是依據元素的訪問方式,分成順序容器、有序容器和無序容器三大類別。

1. 容器的基本特徵

容器就是對數據結構的抽象和封裝,即能夠“容納”“存放”元素的一些數據結構。
C++ 標準庫裏的容器幫助我們實現了最基本和最經典的數據結構,且容器的性能和優化水平已經非常完善,這一塊不需要自己造輪子。
容器的基本特性:保存元素採用的是“值”(value)語義,容器裏存儲的是元素的拷貝、副本,而不是引用

關於拷貝操作

容器操作元素的很大一塊成本就是值的拷貝,如果元素比較大,或者非常多,那麼操作時的拷貝開銷就會很高,性能也就不會太好。常用的解決方法如下:

  • 方法1:爲元素實現轉移構造和轉移賦值函數,在加入容器的時候使用 std::move() 來“轉移”,減少元素複製的成本:
Point p;                        // 一個拷貝成本很高的對象

v.push_back(p);                // 存儲對象,拷貝構造,成本很高
v.push_back(std::move(p));    // 定義轉移構造後就可以轉移存儲,降低成本
  • 方法2:使用 C++11 爲容器新增加的 emplace 操作函數,它可以“就地”構造元素,免去了構造後再拷貝、轉移的成本,不但高效,而且用起來也很方便:
v.emplace_back(...);            // 直接在容器裏構造元素,不需要拷貝或者轉移
  • 方法3: 使用指針
    可以使用智能指針 unique_ptr/shared_ptr,來自動管理元素。
    一般情況下,shared_ptr 是一個更好的選擇,它的共享語義與容器的值語義基本一致。
    使用 unique_ptr 就要當心,它不能被拷貝,只能被轉移

注意: 不建議在容器裏存放元素的指針,來間接保存元素。
原因: 指針的開銷很低,但因爲它是“間接”持有,導致不能利用容器自動銷燬元素的特性,而且必須要自己手動管理元素的生命週期,非常容易出錯,且有內存泄漏的隱患。

2. 容器的具體分類

C++中標準容器分3類:順序容器、有序容器和無序容器,如下圖,圖片來自[羅劍鋒c++實戰筆記]:
圖片來自優先選擇的應該是 array 和 vector,因爲速度最快,開銷最低;

  • list 是鏈表結構,插入刪除的效率高,但查找效率低;
  • 有序容器是紅黑樹結構,對 key 自動排序,查找效率高,但有插入成本;
  • 無序容器是散列表結構,由 hash 值計算存儲位置,查找和插入的成本都很低;
  • 有序容器和無序容器都屬於關聯容器,元素有 key 的概念,操作元素實際上是在操作 key,所以要定義對 key 的比較函數或者散列函數。

Trick:多利用類型別名,而不要“寫死”容器定義。因爲容器的大部分接口是相同的,所以只要變動別名定義,就能夠隨意改換不同的容器,對於開發、測試都非常方便。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章