C++ vector用法詳解

2021-02-19 科學計算Tech
vector概述

  vector是種容器,類似數組一樣,但它的size可以動態改變。

  vector的元素在內存中連續排列,這一點跟數組一樣。這意味著我們元素的索引將非常快,而且也可以通過指針的偏移來獲取vector中的元素。

  但連續排列也帶來了弊端,當我們向vector中間插入一個數據時,整個vector的size變大,在內存中就需要重新分配空間,常規的做法是直接申請一個新的array,並將所有元素拷貝過去;但這麼做的話,無疑太浪費時間,因此vector採用的做法是:vector會分配額外的空間,以適應size的動態增長。因此,包含同樣數量元素的vector和數組相比,佔用的空間會更大。而且在vector最後增加或者刪除一個元素,消耗的時間是一個常數值,與vector的size無關。

  與其他容器(deques、lists、forward_lists)相比,vector在獲取元素和對最後一個元素的操作效率上更高;但對於中間元素的操作,性能則相對較差。

vector的使用頭文件

#include <vector>

創建vector對象

std::vector<int> vec1;                                // 空的vector,數據類型為int
std::vector<int> vec2(4);                             // 4個值為0的vector
std::vector<int> vec3 (4,10);                         // 4個值為10的vector [10 10 10 10]
std::vector<int> vec4 (vec3.begin(),vec3.end());      // [10 10 10 10]
std::vector<int> vec5 (vec3);                         // [10 10 10 10]
std::vector<int> vec6 = {10, 20, 30, 40};             // [10 20 30 40]

屬性及操作

Iterators

NameDescriptionbegin返回指向迭代器第一個元素的指針end返回指向迭代器最後一個元素的指針rbegin返回迭代器逆序第一個元素的指針rend返回迭代器逆序最後一個元素的指針cbegin返回常量迭代器的第一個元素的指針cend返回常量迭代器的最第一個元素的指針crbegin返回常量迭代器逆序的第一個元素的指針crend返回常量迭代器逆序的最後一個元素的指針




Capacity

NameDescriptionsize返回當前vector使用數據量的大小max_size返回vector最大可用的數據量resize調整vector中的元素個數capacity返回vector中總共可以容納的元素個數empty測試vector是否是空的reserve控制vector的預留空間shrink_to_fit減少capacity到size的大小




Element access

NameDescriptionoperator[]在[]中可以做運算atvector.at(i)相當於vector[i]front返回第一個元素的值back返回最後一個元素的值data返回指向vector內存數據的指針




Modifiers

NameDescriptionassign指定vector內容push_back在容器的最後一個位置插入元素xpop_back刪除最後一個元素insert插入元素erase擦除元素swap交換兩個容器的內容clear將容器裡的內容清空,size值為0,但是存儲空間沒有改變emplace插入元素(與insert有區別)emplace_back在容器的最後一個位置插入元素x(與push_back有區別)




Allocator

NameDescriptionget_allocator返回vector的內存分配器




具體使用方法

Iterators

  Iterators使用方式比較簡單,下面的程序也很直觀的展現了它們的用法。其中it3和it4在for中使用auto來定義,使用更加方便。

#include <iostream>
#include <vector>

using namespace std;

int main() {
    vector<int> vec0;

    for (int i = 0; i < 10; ++i) {
        vec0.push_back(i);            //[0,1,2,3,4,5,6,7,8,9]
    }

    vector<int>::iterator it1;
    for (it1 = vec0.begin(); it1 != vec0.end(); ++it1) {
        cout << ' ' << *it1 << endl;   //[0,1,2,3,4,5,6,7,8,9]
    }

    vector<int>::reverse_iterator it2;
    for (it2 = vec0.rbegin(); it2 != vec0.rend(); ++it2) {
        cout << ' ' << *it2 << endl;   //[9,8,7,6,5,4,3,2,1,0]
    }

    for (auto it3 = vec0.cbegin(); it3 != vec0.end(); ++it3) {
        cout << ' ' << *it3 << endl;    //[0,1,2,3,4,5,6,7,8,9]
    }

    for (auto it4 = vec0.crbegin(); it4 != vec0.crend(); ++it4) {
        cout << ' ' << *it4 << endl;    //[9,8,7,6,5,4,3,2,1,0]
    }

    return 0;
}

  如果是vec0.begin()+1,則表示從第二個元素開始。

Capacity

  Capacity中的幾個函數,從描述上看有點模糊,下面我們具體解釋一下。

  

size返回的是當前vector中有多少元素;

max_size返回的是最大可用的數據量,這跟實際的硬體有關,但也並不是所有的內存空間都可用,比如下面程序中的運行的內存大小為32GByte,但返回的結果是4GByte;

capacity是當前vector分配的可以容納的元素個數,下面的代碼中,vec0可以容納13個元素,但僅包含了size(即10)個元素,還有3個元素可以放進去,當再放入超過3個元素後,vec0就會被重新分配空間;所以,capacity始終大於等於size

resize把容器改為容納n個元素。調用resize之後,size將會變為n;其中n又分了三種情況,當n

<size時,容器尾部的元素會被銷毀,capacity保持不變;當size<n≤capacity時,新增加的元素都是0,capacity保持不變;當n style="font-size: inherit;color: inherit;line-height: inherit;">capacity時,size和capacity同時變為n,新增加的元素都是0;</size時,容器尾部的元素會被銷毀,capacity保持不變;當size<n≤capacity時,新增加的元素都是0,capacity保持不變;當n>

empty比較簡單,當vector為空時,返回1,不為空返回0;

shrink_to_fit,去掉預留的空間,capacity與size保持一致

#include <iostream>
#include <vector>

using namespace std;

int main() {
    vector<int> vec0;
    cout << "vec0 empty status:" << vec0.empty() << endl;   // 1

    for (int i = 0; i < 10; ++i) {
        vec0.push_back(i);            //[0,1,2,3,4,5,6,7,8,9]
    }

    cout << "vec0 empty status:" << vec0.empty() << endl;   // 0

    //Capacity-
    cout << "vec0 size:" << vec0.size() << endl;          //10
    cout << "vec0 max size:" << vec0.max_size() << endl;  //1073741823 = 4GByte
    cout << "vec0 capacity:" << vec0.capacity() << endl;  //13
    vec0.resize(20);
    cout << "new size:" << vec0.size() << "  new capacity:" << vec0.capacity() << endl;  //20 20
    vec0.resize(5);
    cout << "new size:" << vec0.size() << "  new capacity:" << vec0.capacity() << endl;  // 5 20
    vec0.shrink_to_fit();
    cout << "new size:" << vec0.size() << "  new capacity:" << vec0.capacity() << endl;  // 5 5

    return 0;
}

#include <iostream>
#include <vector>

using namespace std;

int main() {
    //reserve----
    std::vector<int> vec0;
    int sz;
    sz = vec0.capacity();
    std::cout << "making vec0 grow:\n";
    for (int i = 0; i < 100; ++i) {
        vec0.push_back(i);
        if (sz != vec0.capacity()) {
            sz = vec0.capacity();
            std::cout << "capacity changed: " << sz << '\n';
        }
    }

    std::vector<int> vec1;
    sz = vec1.capacity();
    vec1.reserve(100);   // this is the only difference with vec0 above
    std::cout << "making vec1 grow:\n";
    for (int i = 0; i < 100; ++i) {
        vec1.push_back(i);
        if (sz != vec1.capacity()) {
            sz = vec1.capacity();
            std::cout << "capacity changed: " << sz << '\n';
        }
    }
    return 0;
}

列印結果為:

making vec0 grow:
capacity changed: 1
capacity changed: 2
capacity changed: 3
capacity changed: 4
capacity changed: 6
capacity changed: 9
capacity changed: 13
capacity changed: 19
capacity changed: 28
capacity changed: 42
capacity changed: 63
capacity changed: 94
capacity changed: 141
making vec1 grow:
capacity changed: 100

Element access

  vector元素獲取的使用方法也比較簡單,下面的代碼可以很好的展示:

vector<int> vec0;
for (int i = 0; i < 10; ++i) {
    vec0.push_back(i);            //[0,1,2,3,4,5,6,7,8,9]
}

for (unsigned int i = 0; i < vec0.size(); ++i) {
        cout << vec0.at(i) << endl;       //[0,1,2,3,4,5,6,7,8,9]
    }

    cout << "front element:" << vec0.front() << endl;  //0
    cout << "back element:" << vec0.back() << endl;    //9

    vector<int>vec1(5);             // [0,0,0,0,0]
    int *p = vec1.data();           // vec1 must not be empty
    for (unsigned int i = 0; i < vec1.size(); ++i) {
        *p = i;
        ++p;
    }
    for (unsigned int i = 0; i < vec1.size(); ++i) {
        cout << vec1[i] << endl;    // [0,1,2,3,4]
    }

Modifiers

  assign主要有三種用法,如下面的demo所示:

vector<int> vec1;
vector<int> vec2;
vector<int> vec3;

vec1.assign(5, 10);               //[10,10,10,10,10]

vector<int>::iterator it;
it = vec1.begin() + 1;

vec2.assign(it, vec1.end() - 1);  //[10,10,10]

int arr[] = { 10,20,30,40};
vec3.assign(arr, arr + 4);        //[10,20,30,40]

  push_back和pop_back用法比較簡單

vec0.push_back(55);
cout << "Last element:" << vec0.back() << "  size: " << vec0.size()<< endl;  //55 11
vec0.pop_back();
cout << "Last element:" << vec0.back() << "  size: " << vec0.size() << endl; //9 10

  在vector中,有插入元素功能的函數有四個:push_back、insert、emplace和emplace_back,其中push_back上面講了,emplace_back是在C++11中引入的,用法跟push_back完全一樣,都是在vector的最後插入一個元素。

vec3.emplace_back(100);

那為什麼要引入一個用法完全一樣的函數?因為它們的底層實現方式不同,push_back向容器尾部添加元素時,然後再將這個元素拷貝或者移動到容器中(如果是拷貝的話,事後會自行銷毀先前創建的這個元素);而 emplace_back 在實現時,則是直接在容器尾部創建這個元素,省去了拷貝或移動元素的過程。

  insert和emplace(C++11中引入)都可以向vector中間插入元素,但insert可以插入多個元素,emplace一次只能插入一個元素。

  insert有三種用法:

在指定位置loc前插入值為val的元素,返回指向這個元素的迭代器,

在指定位置loc前插入num個值為val的元素

在指定位置loc前插入區間[start, end)的所有元素

// method1
vector<int> vec1;
int arr[] = { 1,2,3,4,5 };
vec1.insert(vec1.begin(), arr, arr + 5);     //[1,2,3,4,5]

// method2
vector<int> vec2(vec1); 
vector<int>::iterator it = vec1.begin() + 2;
vec1.insert(it, 3, 20);                      // [1,2,20,20,20,3,4,5]

// method3
vector<int> vec3(3, 40);
vector<int>::iterator it2 = vec2.begin();
vec2.insert(it2, vec3.begin(), vec3.end());  // [40,40,40,1,2,3,4,5]

  emplace的使用方式為:

iterator emplace (const_iterator pos, args...);

vector<int> vec0{1,2,3};
vec0.emplace(vec0.begin()+2,10);    //[1,2,10,3]

  若都是插入一個元素的情況下,該使用哪個函數呢?當然是C++11中新引入的emplace,emplace在插入元素時,在指定位置直接構造元素,而insert是生成元素,再將其賦值或移動到容器中。

  vector中有三種可以刪除元素的操作,第一種就是我們上面講到的pop_back,刪除最後一個元素,無返回值;第二種是clear,將容器清空,size變為0,無返回值;第三種是erase,通過迭代器來刪除元素,可以刪除一個元素,也可以刪除某個範圍內的元素,返回下一個位置的迭代器。

vector<int> vec0{ 1,2,3,4,5,6,7,8,9,10};
//for (int i = 0; i < 4; ++i) {
//    vec0.pop_back();
//}
vec0.erase(vec0.begin() + 3);               // [1,2,3,5,6,7,8,9,10]
vec0.erase(vec0.begin(), vec0.begin() + 5); // [7,8,9,10]
//vec0.clear();

  swap的用法也比較簡單,就是交換兩個vector的內容

vector<int> vec1{ 1,2,3,4,5 };
vector<int> vec2{ 10,20,30 };
vec1.swap(vec2);

Allocator

  get_allocator用的不是特別多,我們把使用方法講一下。

vector<int> myvector;
int * p;
unsigned int i;

// 使用Allocator為數組分配5個元素的空間
p = myvector.get_allocator().allocate(5);


for (i=0; i<5; i++) myvector.get_allocator().construct(&p[i],i);

std::cout << "The allocated array contains:";
for (i=0; i<5; i++) std::cout << ' ' << p[i];    //[0,1,2,3,4]


for (i=0; i<5; i++) myvector.get_allocator().destroy(&p[i]);
myvector.get_allocator().deallocate(p,5);

二維數組

  上面我們講的,都相當於是一維數組,vector還支持二維數組,但這種二維數組是通過嵌套的方式來實現,並不像Python或者Matlab的矩陣那麼直觀。

vector<vector<int>> arr(3);
for (int i = 0; i < 3; ++i) {
    arr[i].resize(3);           //3x3 array
}
for (int i = 0; i < 3; ++i) 
    for (int k = 0; k < 3; ++k) 
        arr[i][k] = i * k;      // 賦值
arr.resize(4);                  // 二維數組包含4個變量
arr[2].resize(5);               // 第3個變量包含5個變量

相關焦點

  • C++ vector詳解
    可以簡單的認為,vector是一個能夠存放任意類型的動態數組。接下來,請跟隨小編一起來複習一下吧。以下是正文前言本文mark了vector的一些接口,介紹了vector中的對內存和對象的管理詳解請見cppreference-vector。
  • C++11學習 - Array的用法與vector用法
    作者丨淡淡_小孩https://blog.51cto.com/13475106/2554602C++11學習 - Array的用法與
  • C++打怪 之 vector
    基本用法C++ 中的vector實現實用的接口供開發者選擇://頭文件#include <vector> using namespace std;/* 構造方法 */vector<類型>標識符vector<類型&
  • C++ initializer_list 詳解
    用於表示某種特定類型的值的數組,和vector一樣,initializer_list也是一種模板類型。和使用vector一樣,我們也可以使用迭代器訪問initializer_list裡的元素void error_msg(initializer_list<string> il){ for(auto beg=il.begin();beg!
  • 還不懂c++vector的用法,你憑什麼勇氣來的!
    今天給大家帶來一篇c++vector的介紹,難以置信這篇文章寫了我三天,不過總算整理完畢,現在分享給大家。模板類vector 和 array是數組的替代品。模板類vector 類似於string類,也是一種動態數組。 在 c++ 中,vector 是一個十分有用的容器。
  • C++逆向學習(二) vector
    現在的逆向C++題越來越多,經常上來就是一堆容器、標準模板庫,這個系列主要記錄這些方面的逆向學習心得本文主要介紹std::vector,因為逆向題中的C++代碼可能會故意寫的很繞,比如輸入一個數組,直接給vector賦值即可,但是也可以用稍微費解的方法連續push_back(),也算是一種混淆的手段,文章中的示例會逆向一些故意寫的繁瑣的程序vector內存布局
  • ​跟我學C++中級篇——STL的容器vector
    一、順序容器vectorC++程式設計師中,如果用到過STL,那麼一定肯定用過vector,這個是最常見,最初步的一個數據類型。上一篇提到的array遠遠比不上它。畢竟那玩意兒相對vector是很久遠後才提出來的。在這之前,std::vector承擔了多少小菜鳥處理數組各種問題的最優選方法。不用處理內存,可以刪除,任意增加不考慮越界。那簡直是一種最單純質樸的快樂。
  • 6 個技巧,提升 C++11 的 vector 性能
    馬上開始在 C++ 11 中優化 vector 用法的介紹。這種情況下,可以使用「Swap 慣用法」來清空 vector,代碼如下:container<T>( c ).swap( c ); // shrink-to-fit 慣用法,用於清空存儲空間container<T>().swap( c );    // 用於清空所有內容和存儲空間的慣用法 如果你對此感興趣,請查看「C++ Coding
  • C vector詳解
    可以簡單的認為,vector是一個能夠存放任意類型的動態數組。接下來,請跟隨小編一起來複習一下吧。以下是正文前言本文mark了vector的一些接口,介紹了vector中的對內存和對象的管理詳解請見cppreference-vector。
  • C++ 優先隊列priority_queue
    Container 還必須要支持隨機訪問,並且有 front()、push_back()、pop_back() 等函數這樣來看只有 std::vector、std::deque 滿足容器條件了,而優先隊列中使用的默認參數也是 std::vector。
  • 詳解C++中的vector 利用swap去除多餘容量
    在使用C++中的 vector的時候,vector的申請的內存不會自動釋放,當 push_back的時候,如果 vector的當前內存不夠使用的時候,vector會自動的二倍增長內存,可能會導致最後內存不斷的增多。下面我們介紹幾種避免這種情況的技巧。
  • C 2 C++進階篇(1)
    之前一直是對於面向過程的編程,python有過那種對象風格的編程,但是對於oop的實際開發還停留在表面,沒有獨立的開發c++經驗,也有好幾年沒有碰過c了。由於接手Qt的相關項目,所以對c to c++的進階希望能進行個自我總結。
  • C++之旅-vector
    初始化與string類型一樣,vector也有很多種方式進行初始化:vector<int> v1;    vector<int> v2(v1);  vector<int> v2 = v1; vector<string> v3(3,"hello"); vector<string>
  • 跟我學C++中級篇——STL的學習
    一、c++標準庫C++的標準庫主要包含兩大類,首先是包含C的標準庫的,當然,為了適應c++對一些C庫進行了少許的修改和增加。最重要的當然是面向對象的c++庫;而c++庫又可以分成兩大類,即面向對象的c++庫和標準模板庫,也就是題目中的STL。
  • C++ sort 排序函數用法
    (給CPP開發者加星標,提升C/C++技能)https://blog.csdn.net/w_linux/article/details/76222112最近在刷ACM經常用到排序,以前老是寫冒泡,可把冒泡帶到OJ裡後發現經常超時,所以本想用快排,可是很多學長推薦用sort函數,因為自己寫的快排寫不好真的沒有sort快,所以毅然決然選擇sort函數用法
  • json for modern c++的使用
    今天介紹的json版本是在c++下使用的,是一個開源項目。GitHub開源項的地址:https://github.com/nlohmann/jsonjson for modern c++是一個德國大牛nlohmann寫的,該版本的json有以下特點:1.直觀的語法。
  • C++隨機排序容器中的元素
    作者:apocelipes連結:https://www.cnblogs.com/apocelipes/p/10351335.html在各種程序語言中都提供了將容器元素隨機排序的shuffle方法,c++
  • C++卡牌小遊戲
    以前上學的時候業餘學了點c++ ,也僅僅用來做過一個控制臺版的「學生管理系統」,現在工作接觸最多的還是C語言,c++那各種屌炸天的語法和
  • 「最佳實踐」C++陷阱與套路
    # 三、性能## 空間置換時間通過空間換取時間是提高性能的慣用法,bitmap,int map[]這些慣用法要瞭然於胸。3. resize()是重置大小;reserve()是預留空間,並未改變size(),可避免多次擴容;clear()並不會導致空間收縮 ,如果需要釋放空間,可以跟空的vector交換,std::vector <t>.swap(v),c++11裡shrink_to_fit()也能收縮內存。4.
  • c++11新特性,所有知識點都在這了!
    c++11新特性吧,你是怎麼回答的呢?本文基本上涵蓋了c++11的所有新特性,並有詳細代碼介紹其用法,對關鍵知識點做了深入分析,對重要的知識點我單獨寫了相關文章並附上了相關連結,我整理了完備的c++新特性腦圖(由於圖片太大,我沒有放在文章裡,同學可以在後臺回復消息「新特性」,即可下載完整圖片)。