C++ vector 标准库总结

标准库文档:C++ vector

基本介绍(可以跳过,只是一些原理介绍)

vector 是序列容器,表示可以改变大小的数组。就像数组一样,vector 为它们的元素使用连续的存储位置,这意味着它们的元素也可以使用指向其元素的常规指针上的偏移量来访问,并且与数组一样高效。但与数组不同,它们的大小可以动态变化,容器会自动处理它们的存储。

在内部,vector 使用动态分配的数组来存储它们的元素。这个数组可能需要重新分配,以便在插入新元素时增大大小,这意味着分配一个新数组并将所有元素移动到其中。就处理时间而言,这是一个相对昂贵的任务,因此,vector 不会在每次向容器添加元素时就重新分配。相反,vector 容器可能分配一些额外的存储空间以适应可能的增长,因此容器的实际容量可能大于包含其元素所需的存储空间(即它的大小)。

库可以实现不同的策略来平衡内存使用和重新分配的问题,但在任何情况下,重新分配应该只发生在对数生长间隔的大小,以便插入单个元素的向量可以提供平摊常数时间复杂度(见push_back方法)。因此,与数组相比,向量消耗更多的内存,以换取管理存储和有效地动态增长的能力。与其他动态序列容器(deques、lists和forward_lists)相比,vector 非常高效地访问它的元素(就像数组一样),并且相对高效地从它的末尾添加或删除元素。对于涉及在非结尾位置插入或删除元素的操作,它们的性能比其他操作差,而且迭代器和引用的一致性比list和forward_lists差。

方法

  1. 构造函数
  std::vector<int> first;                                // empty vector of ints
  std::vector<int> second (4,100);                       // four ints with value 100
  std::vector<int> third (second.begin(),second.end());  // iterating through second
  std::vector<int> fourth (third);                       // a copy of third

  // the iterator constructor can also be used to construct from arrays:
  int myints[] = {16,2,77,29};
  std::vector<int> fifth (myints, myints + sizeof(myints)/sizeof(int));  //等价于third
  
  std::vector<int> sixth = {10,20,30,40}
  ====>
  first = {}
  seconde = {100,100,100,100}
  third = {100,100,100,100}
  forth = {100,100,100,100}
  fifth = {16,2,77,29}
  sixth = {10,20,30,40}

第一种方法是默认的,创建了一个空的vector;第二种方法是构造的4个值为100的int类型vector;第三种第四种都是复制的第二个;第五种等价于第三种,使用头指针和尾指针的形式来传值的。

  1. 析构函数
    ~vector()
  2. = 等号
    将新内容分配给容器,替换其当前内容,并相应地修改其大小。
  3. Iterators:
    std::vector<int> myvector (5);  // 5 default-constructed ints
    for (std::vector<int>::iterator it = myvector.begin(); it != myvector.end(); ++it)
        std::cout << ' ' << *it;
    std::cout << '\n';  //输出初始值

    int i=0;
    std::vector<int>::iterator rit = myvector.begin();
    for (; rit!= myvector.end(); ++rit)
        *rit = ++i;  //进行赋值
    std::cout << "my vector contains:";
    for (std::vector<int>::iterator it = myvector.begin(); it != myvector.end(); ++it)
        std::cout << ' ' << *it;
    std::cout << '\n';  //输出正向的数据{1,2,3,4,5}

    std::cout << "my vector contains:(reverse)";
    for (std::vector<int>::reverse_iterator rit = myvector.rbegin(); rit != myvector.rend(); ++rit)
        std::cout << ' ' << *rit;
    std::cout << '\n';  //输出反向的数据{5,4,,3,2,1}

    std::vector<int> myvector = {10,20,30,40,50};
    auto it = myvector.cbegin();
    vector<int>::iterator it2 = myvector.begin();
    *it2 = 12;
    // *it = 14; 会报错。
    for (;it!=myvector.end();++it){
        std::cout<<' '<<*it;
    }
    std::cout<<'\n'; // 输出{12,20,30,40,50}
Iterators 作用
begin 返回vector 开始
end 返回vector 结束
rbegin 返回逆向的vector 的开始
rend 返回逆向的vector 的结束
cbegin 返回const 类型的开始指针,意思就是说,vector 的值不能像 *begin = 0 这样被改变
cend 返回const 类型的结束指针
crbegin 返回const 类型的逆向开始指针
crend 返回const 类型的逆向结束指针
  1. Capacity
    其中 size 等等的类型都是std::vector<*>::size_type,成员类型size_type是无符号整数类型。
Capacity 使用
size myvector.size() : 这是向量中实际持有的对象的数量,这并不一定等于它的存储容量。
capacity myvector.capacity() : 返回当前分配给向量的存储空间的大小,用元素表示。
max_size myvector.max_size() : 由于已知的系统或库实现限制,这是容器能够达到的最大潜在大小,但是容器并不能保证能够达到这个大小:在达到这个大小之前,它仍然可能无法分配存储空间。
resize myvector.resize(): 调整容器的大小,使其包含n个元素。直接对size 进行操作的
empty myvector.empty(): 如果容器大小为0,则为true,否则为false。
reverse myvector.reverse() :直接改变的是capacity ,使得capacity 变成reverse参数中设置的那个值
shrink_to_fit myvector.shrink_to_fit():直接改变的是capacity ,相当于让capacity = size

下面这些程序能让你更好的理解 .resize() 和 .capacity():

    std::vector<int> myvector;
    cout<<myvector.capacity()<<endl;  //0
    // set some initial content:
    for (int i=1;i<10;i++) myvector.push_back(i);   //1 2 3 4 5 6 7 8 9
    cout<<myvector.capacity()<<endl;  //16
    
    myvector.resize(5);
    cout<<myvector.capacity()<<endl;   //16
    std::cout << "myvector contains:";
    for (int i=0;i<myvector.size();i++)
        std::cout << ' ' << myvector[i];
    std::cout << '\n';  //1 2 3 4 5

    myvector.resize(8,100);
    std::cout << "myvector contains:";
    for (int i=0;i<myvector.size();i++)
        std::cout << ' ' << myvector[i];
    std::cout << '\n';  //1 2 3 4 5 100 100 100

    myvector.resize(12);
    std::cout << "myvector contains:";
    for (int i=0;i<myvector.size();i++)
        std::cout << ' ' << myvector[i];
    std::cout << '\n';  // 1 2 3 4 5 100 100 100 0 0 0 0

下面这些程序能让你更好的理解 .reserve():

std::vector<int>::size_type sz;

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

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

=======>
making foo grow:
capacity changed: 1
capacity changed: 2
capacity changed: 4
capacity changed: 8
capacity changed: 16
capacity changed: 32
capacity changed: 64
capacity changed: 128
making bar grow:(reserve)
capacity changed: 100

下面这些代码能让你理解 .shrink_to_fit()

  std::vector<int> myvector (100);
  std::cout << "1. capacity of myvector: " << myvector.capacity() << '\n';

  myvector.resize(10);
  std::cout << "2. capacity of myvector: " << myvector.capacity() << '\n';

  myvector.shrink_to_fit();
  std::cout << "3. capacity of myvector: " << myvector.capacity() << '\n';
  1. Modifiers
Modifiers 作用
assign 将新内容分配给向量,替换其当前内容,并相应地修改其大小。
push_back 在末尾添加元素
pop_back 删除最后一个元素
insert 返回逆向的vector 的结束
erase 从向量中删除单个元素(位置)或元素范围([first,last])。
swap 交换两个vector
clear 全清空
emplace 给指针的形式插入元素,并返回这个插入位置的指针
emplace_back 类似于push_back

理解assign:

std::vector<int> first;
    std::vector<int> second;
    std::vector<int> third;

    first.assign (7,100);             // 7 ints with a value of 100

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

    second.assign (it,first.end()-1); // the 5 central values of first

    int myints[] = {1776,7,4};
    third.assign (myints,myints+3);   // assigning from array.

    std::cout << "Size of first: " << int (first.size()) << '\n';
    std::cout << "Size of second: " << int (second.size()) << '\n';
    std::cout << "Size of third: " << int (third.size()) << '\n';

理解 insert:

    std::vector<int> myvector {1,2,3};
    std::vector<int>::iterator it;

    it = myvector.begin();
    it = myvector.insert ( it , 200 );

    myvector.insert (it,2,300); //在it指向的位置插入两个 300

    // "it" no longer valid, get a new one:
    it = myvector.begin();

    std::vector<int> anothervector (2,400);
    myvector.insert (it+2,anothervector.begin(),anothervector.end());

    int myarray [] = { 501,502,503 };
    myvector.insert (myvector.begin(), myarray, myarray+3);

    std::cout << "myvector contains:";
    for (it=myvector.begin(); it<myvector.end(); it++)
        std::cout << ' ' << *it;
    std::cout << '\n';

理解erase:

  std::vector<int> myvector;

  // set some values (from 1 to 10)
  for (int i=1; i<=10; i++) myvector.push_back(i);

  // erase the 6th element
  myvector.erase (myvector.begin()+5);

  // erase the first 3 elements:
  myvector.erase (myvector.begin(),myvector.begin()+3);

理解swap:

    std::vector<int> foo (3,100);   // three ints with a value of 100
    std::vector<int> bar (5,200);   // five ints with a value of 200

    foo.swap(bar);
    //foo contains: 200 200 200 200 200
    //bar contains: 100 100 100

理解clear():

   std::vector<int> myvector;
  myvector.push_back (100);
  myvector.push_back (200);
  myvector.push_back (300);

  std::cout << "myvector contains:";
  for (unsigned i=0; i<myvector.size(); i++)
    std::cout << ' ' << myvector[i];
  std::cout << '\n';  //{300,200,100}

  myvector.clear();
  myvector.push_back (1101);
  myvector.push_back (2202);

  std::cout << "myvector contains:";
  for (unsigned i=0; i<myvector.size(); i++)
    std::cout << ' ' << myvector[i];
  std::cout << '\n';  //{2202,1101}

理解emplace:

    std::vector<int> myvector = {10,20,30};
    auto it = myvector.emplace ( myvector.begin()+1, 100 );
    myvector.emplace ( it, 200 );
    myvector.emplace ( myvector.end(), 300 );

    std::cout << "myvector contains:";
    for (auto& x: myvector)
        std::cout << ' ' << x;
    std::cout << '\n';
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,036评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,046评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,411评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,622评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,661评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,521评论 1 304
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,288评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,200评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,644评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,837评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,953评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,673评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,281评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,889评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,011评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,119评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,901评论 2 355

推荐阅读更多精彩内容

  • STL部分 1.STL为什么广泛被使用 C++ STL 之所以得到广泛的赞誉,也被很多人使用,不只是提供了像vec...
    杰伦哎呦哎呦阅读 4,321评论 0 9
  • 什么是容器 首先,我们必须理解一下什么是容器,在C++ 中容器被定义为:在数据存储上,有一种对象类型,它可以持有其...
    Jack_Cui阅读 475评论 0 2
  • 前言 把《C++ Primer》[https://book.douban.com/subject/25708312...
    尤汐Yogy阅读 9,517评论 1 51
  • 标签(空格分隔): STL 运用STL,可以充分利用该库的设计,让我为简单而直接的问题设计出简单而直接的解决方案,...
    认真学计算机阅读 1,480评论 0 10
  • 昨晚做了一个很奇怪的梦,可以用胡乱郁闷来形容。就像是那些名画大家要表现一些荒诞事实的画一样,夸张,阴郁的能出水。这...
    d630dc51b0e5阅读 204评论 0 0