STL容器---Vector

TelSunny發表於2021-12-16

1.底層實現原理

  1. vector的底層資料結構比較簡單,時一段連續的儲存空間,即陣列。

    //_Alloc 表示記憶體分配器,此引數幾乎不需要我們關心
    template <class _Ty, class _Alloc = allocator<_Ty>>
    class vector{
        ...
    protected:
        pointer _Myfirst;
        pointer _Mylast;
        pointer _Myend;
    };
    

    從它的原始碼中可以看出,它是通過三個指標來實現的。

    • _Myfirst 指向的是 vector 容器物件的起始位元組位置;
    • _Mylast 指向當前最後一個元素的末尾位元組;
    • _Myend 指向整個 vector 容器所佔用記憶體空間的末尾位元組。

    通過這三個指標來完成各種功能,下面舉幾個例子說明,詳細說明在API函式中會進行講解。

    • iterator begin() {return _Myfirst;}
    • iterator end() {return _Mylast;}
    • size_type size() const {return size_type(end() - begin());}
    • size_type capacity() const {return size_type(_Myend - begin());}
    • bool empty() const {return begin() == end();}
    • reference operator[] (size_type n) {return *(begin() + n);}
    • reference front() { return *begin();}
    • reference back() {return *(end()-1);}

    注意:當vector為空時,三個指標都為null!

  2. vector的擴容

    vector是自動擴容的,當插入的資料大於當前vector的容量時,不同編譯器的擴容是不一樣的,VS本身就會自動擴大容量50%。
    擴容過程如下所示:

    • 找到一塊新的地址空間,申請連續空間。
    • 將舊空間中的資料按順序移動到新地址空間中。
    • 釋放掉舊空間中的記憶體。

2.常用的API函式

函式名 功能
empty(); 判斷vector是否為空
capacity(); 容器的容量
size(); 容器資料的數量(大小)
push_back(elem); 在尾部插入一個元素
pop_back(elem); 刪除尾部的一個元素
assign(beg, end); 區間中的資料拷貝賦值給本身
assign(n,elem); 將n個elem拷貝賦值給本身
insert(const_iterator pos, (count),elem); 在pos位置插入(count)個elem元素
erase(const_iterator pos); 刪除指定位置的元素
clear(); 清空所有位置的元素
reserve(int len); 設定vector的容量
at(int idx); 根據索引取值
operator[]; 返回索引idx所指的資料
front(); 返回容器中第一個資料元素
back(); 返回容器中最後一個資料元素

另外c++11對push_back()進行了改進,提供了emplace_back()函式。
它們的區別主要在於是否進行了深度拷貝或者移動建構函式。

  • push_back(Person)

    • 首先建立Person物件。
    • 把Person複製到vector的尾部元素(拷貝/移動構造)。若是深拷貝,那麼會影響效能,佔用更多的堆空間。
    • 若是拷貝需要銷燬掉之前建立好的物件。
  • emplace_back(Person)
    直接在vector的尾部新建物件。
    程式碼實現如下所示。

    void* ptr = malloc(sizeof(Person)); 
    new (ptr)Person();
    

    第1行: 主要是分配一個Person物件所需的記憶體空間, 但在vector裡, 這步不需要考慮, 內部會在實現;
    第2行: 這才是重點, 通過這樣的語法, 就可以對已在的記憶體空間, 呼叫相應的Person類建構函式進行初始化;

同理emplace與insert也是一樣的道理

3.迭代器失效解決辦法

  1. reserve()函式對vector進行擴容時,會造成迭代器失效。
  2. erase()函式刪除元素時,返回值就是下一個迭代器,在迴圈時容易造成迭代器丟失。

4.參考文獻

vector底層實現機制
vector的函式使用
push_back()和emplace_back()詳解
移動建構函式詳解

相關文章