C++ STL Vector容器

一、前言

vector和array的不同之处在于:array 实现的是静态数组(容量固定的数组),而 vector 实现的是一个动态数组。
vector 容器以类模板 vector<T>( T 表示存储元素的类型)的形式定义在 <vector> 头文件中,并位于 std 命名空间中。因此,在创建该容器之前,代码中需包含如下内容:

#include <vector>
using namespace std;

说明:std命名空间也可在使用vector容器时额外注明,如:

std::vector<double> values;

二、创建vector的方式

①std::vector<int> vecInt;
②std::vector<int> vecInt {1,5,23,45,87};
③std::vector<int> vecInt(10);
④std::vector<int> vecInt(10, 4);

①方式创建一个空的vector容器,因为容器中没有元素,所以没有分配空间,当用户添加元素时,vector会自动分配内存空间。如果创建好的vector容器的容量不足,可通过reserve()增加容器的容量。需要注意的是:

调用 reserve() 不会影响已存储的元素,也不会生成任何元素,即 vecInt 容器内此时仍然没有任何元素;
如果调用 reserve() 来增加容器容量,之前创建好的任何迭代器(例如开始迭代器和结束迭代器)都可能会失效,因为为了增加容器的容量,vector<T> **容器的元素可能已经被复制或移到了新的内存地址**。

②方式创建一个包含有5个元素的vector容器
③方式创建一个有10个元素、默认初始值为0的vector容器
④方式创建一个有10个元素、指定初始值为4的vector容器
圆括号 () 和大括号 {} 是有区别的,前者表示元素的个数,而后者则表示 vector 容器中的元素值。

三、成员函数

成员函数功能
begin()返回指向容器中第一个元素的迭代器
end()返回指向容器最后一个元素所在位置后一个位置的迭代器,通常和 begin() 结合使用
rbegin()返回指向最后一个元素的迭代器
rend()返回指向第一个元素所在位置前一个位置的迭代器
cbegin()和 begin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素
cend()和 end() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素
crbegin()和 rbegin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素
crend()和 rend() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素
size()返回实际元素个数
max_size()返回元素个数的最大值,一般是 232-1,所以我们很少会用到这个函数
resize()改变实际元素的个数
capacity()返回当前容量
empty()判断容器中是否有元素,若无元素,则返回 true;反之,返回 false
reserve()增加容器的容量
shrink _to_fit()将内存减少到等于当前元素实际所使用的大小
operator[ ]重载了 [ ] 运算符,可以向访问数组中元素那样,通过下标即可访问甚至修改 vector 容器中的元素
at()使用经过边界检查的索引访问元素
front()返回第一个元素的引用
back()返回最后一个元素的引用
data()返回指向容器中第一个元素的指针
assign()用新元素替换原有内容
push_back()在序列的尾部添加一个元素
pop_back()移出序列尾部的元素
insert()在指定的位置插入一个或多个元素
erase()移出一个元素或一段元素
clear()clear()
swap()交换两个容器的所有元素
emplace()在指定的位置直接生成一个元素
emplace_back()在序列尾部生成一个元素
std::swap(x , y)非成员函数,交换数据

四、迭代器的用法

vector的迭代器成员函数和array基本是一样的,如下:
begin()
end()
rbegin()
rend()
cbegin()
cend()
crbegin()
crend()
具体功能图示与https://segmentfault.com/a/11...

1、vector迭代器的独特之处

vector 容器可以随着存储元素的增加,自行申请更多的存储空间。因此,在创建 vector 对象时,我们可以直接创建一个空的 vector 容器,并不会影响后续使用该容器。
vector 容器在申请更多内存后,再次使用之前的迭代器,可能会导致崩溃,因为vector容器在增加容量之后,首个元素的存储地址发生了变化,这个时候再使用之前创建的迭代器显然是错误的,这个时候需要重新初始化迭代器。

五、访问vector容器元素的方式

1、下标方式[]

类似C++中数组的访问方式,vector容器的索引是从0开始的,和数组一样。需要保证下标 n 的值不会超过容器的容量,否则会发生访问越界的错误。

2、at()

当传给at()的索引值越界时,会抛出异常

3、遍历vector容器元素

根据size()获取vector容器的大小,遍历容器中的元素即可
注意:不能使用 capacity() ,因为它返回的是 vector 容器的容量而不是实际存储元素的个数

六、vector容器添加元素

向 vector 容器中添加元素的唯一方式就是使用它的成员函数

1、push_back()

在 vector 容器尾部添加一个元素

2、emplace_back()

C++11新增的,功能和push_back()相同。
既然功能相同,为什么要增加一个emplace_back()呢?

首先我们了解一下emplace_back() 和 push_back() 的区别:底层实现的机制不同。
push_back() 向容器尾部添加元素时,首先会创建这个元素,然后再将这个元素拷贝或者移动到容器中(如果是拷贝的话,事后会自行销毁先前创建的这个元素);而 emplace_back() 在实现时,则是直接在容器尾部创建这个元素,省去了拷贝或移动元素的过程,因此emplace_back()的执行效率比push_back()高。

七、vector插入元素

1、insert()

在 vector 容器的指定位置插入一个或多个元素。该函数的语法格式有多种,如下:

格式说明
iterator insert(pos,elem)在迭代器 pos 指定的位置之前插入一个新元素elem,并返回表示新插入元素位置的迭代器
iterator insert(pos,n,elem)在迭代器 pos 指定的位置之前插入 n 个元素 elem,并返回表示第一个新插入元素位置的迭代器
iterator insert(pos,first,last)在迭代器 pos 指定的位置之前,插入其他容器(不仅限于vector)中位于 [first,last) 区域的所有元素,并返回表示第一个新插入元素位置的迭代器
iterator insert(pos,initlist)在迭代器 pos 指定的位置之前,插入初始化列表(用大括号{}括起来的多个元素,中间有逗号隔开)中所有的元素,并返回表示第一个新插入元素位置的迭代器

2、emplace()

C++ 11中新增的成员函数,用于在 vector 容器指定位置之前插入一个新的元素。

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

pos 为指定插入位置的迭代器;args... 表示与新插入元素的构造函数相对应的多个参数;该函数会返回表示新插入元素位置的迭代器。
注意:
①当拷贝构造函数和移动构造函数同时存在时,insert() 会优先调用移动构造函数。
②实际中,emplace() 的运行效率比insert()高。emplace() 在插入元素时,是在容器的指定位置直接构造元素,而不是先单独生成,再将其复制(或移动)到容器中。

八、 vector删除元素的几种方式

如下:

函数功能
pop_back()删除 vector 容器中最后一个元素,该容器的大小(size)会减 1,但容量(capacity)不会发生改变
erase(pos)删除 vector 容器中 pos 迭代器指定位置处的元素,并返回指向被删除元素下一个位置元素的迭代器。该容器的大小(size)会减 1,但容量(capacity)不会发生改变
swap(beg)、pop_back()先调用 swap() 函数交换要删除的目标元素和容器最后一个元素的位置,然后使用 pop_back() 删除该目标元素
erase(beg,end)删除 vector 容器中位于迭代器 [beg,end)指定区域内的所有元素,并返回指向被删除区域下一个位置元素的迭代器。该容器的大小(size)会减小,但容量(capacity)不会发生改变
remove()删除容器中所有和指定元素值相等的元素,并返回指向最后一个元素下一个位置的迭代器。值得一提的是,调用该函数不会改变容器的大小和容量
clear()删除 vector 容器中所有的元素,使其变成空的 vector 容器。该函数会改变 vector 的大小(变为 0),但不是改变其容量

九、实例

1、访问vector容器中的元素

#include <iostream>
#include <vector>
using namespace std;

int main()
{
    //初始化vector
    std::vector<int> vecInt;
    std::vector<int> vecInt2{ 3,8,9,6,7,10 };
    std::vector<int> vecInt3(10);
    std::vector<int> vecInt4(20, 4);
   
    for (size_t i = 0; i < vecInt.size(); i++)
    {
        std::cout << "vecInt[" << i << "]=" << vecInt[i] << std::endl;
    }
    std::cout << "vecInt size: " << vecInt.size() << " capacity: " << vecInt.capacity() << std::endl;

    for (size_t i = 0; i < vecInt2.size(); i++)
    {
        std::cout << "vecInt2[" << i << "]=" << vecInt2[i] << std::endl;
    }
    std::cout << "vecInt2 size: " << vecInt2.size() << " capacity: " << vecInt2.capacity() << std::endl;

    for (size_t i = 0; i < vecInt3.size(); i++)
    {
        std::cout << "vecInt3[" << i << "]=" << vecInt3[i] << std::endl;
    }
    std::cout << "vecInt3 size: " << vecInt3.size() << " capacity: " << vecInt3.capacity() << std::endl;

    for (size_t i = 0; i < vecInt4.size(); i++)
    {
        std::cout << "vecInt4[" << i << "]=" << vecInt4[i] << std::endl;
    }
    std::cout << "vecInt4 size: " << vecInt4.size() << " capacity: " << vecInt4.capacity() << std::endl;

    system("pause");
    return 0;
}

结果如下:
image.png

2、vector容器迭代器的使用

 //初始化vector
    std::vector<int> vecInt{ 3,8,9,6,7,10,34,57,981,301 };

    //begin、end
    int i = 0;
    std::vector<int>::iterator vecIter = vecInt.begin();
    for (; vecIter != vecInt.end(); vecIter++)
    {
        std::cout << "begin and end test: vecInt[" << i++ << "]=" << *vecIter << std::endl;
    }


    //rbegin、rend
    i = 0;
    std::vector<int>::reverse_iterator vecIterR = vecInt.rbegin();
    for (; vecIterR != vecInt.rend(); vecIterR++)
    {
        std::cout << "rbegin and rend test: vecInt[" << i++ << "]=" << *vecIterR << std::endl;
    }

    //cbegin、cend 
    i = 0;
    std::vector<int>::const_iterator vecIterC = vecInt.cbegin();
    for (; vecIterC != vecInt.cend(); vecIterC++)
    {
        std::cout << "cbegin and cend test: vecInt[" << i++ << "]=" << *vecIterC << std::endl;
    }

    //crbegin、crend
    i = 0;
    std::vector<int>::const_reverse_iterator vecIterCR = vecInt.crbegin();
    for (; vecIterCR != vecInt.crend(); vecIterCR++)
    {
        std::cout << "crbegin and crend test: vecInt[" << i++ << "]=" << *vecIterCR << std::endl;
    }

结果如下:
image.png

3、访问vector容器元素

 //初始化vector
    std::vector<int> vecInt{ 3,8,9,6,7,10,34,57,981,301 };

    //下标方式
    for (int i = 0; i < vecInt.size(); i++)
    {
        std::cout << "vecInt[" << i << "]=" << vecInt[i] << std::endl;
    }

    //at()方式
    for (int i = 0; i < vecInt.size(); i++)
    {
        std::cout << "vecInt[" << i << "]=" << vecInt.at(i) << std::endl;
    }

    //迭代器方式
    int i = 0;
    std::vector<int>::iterator vecIter = vecInt.begin();
    for (; vecIter < vecInt.end(); vecIter++)
    {
        std::cout << " iterator vecInt[" << i++ << "]=" << *vecIter << std::endl;
    }

结果如下:
image.png

4、往vector中插入元素

//初始化vector
    std::vector<int> vecInt{ 3,8,9,6,7,10,34,57,981,301 };

    //添加元素
    vecInt.push_back(4301);
    vecInt.emplace_back(910);

    //下标方式
    for (int i = 0; i < vecInt.size(); i++)
    {
        std::cout << "push_back and emplace_back vecInt[" << i << "]=" << vecInt[i] << std::endl;
    }


    //insert
    vecInt.insert(vecInt.begin(), 72);
    for (int i = 0; i < vecInt.size(); i++)
    {
        std::cout << "insert begin vecInt[" << i << "]=" << vecInt[i] << std::endl;
    }

    vecInt.insert(vecInt.end(), 189);
    for (int i = 0; i < vecInt.size(); i++)
    {
        std::cout << "insert end vecInt[" << i << "]=" << vecInt[i] << std::endl;
    }

    std::array<int, 2> arrayInt{ 13,15 };
    vecInt.insert(vecInt.end(), arrayInt.begin(), arrayInt.end());
    for (int i = 0; i < vecInt.size(); i++)
    {
        std::cout << "insert array vecInt[" << i << "]=" << vecInt[i] << std::endl;
    }

    vecInt.insert(vecInt.end(), { 73,98,49 });
    for (int i = 0; i < vecInt.size(); i++)
    {
        std::cout << "insert array2 vecInt[" << i << "]=" << vecInt[i] << std::endl;
    }

结果如下:
image.png

5、删除vector容器中的元素

  //初始化vector
    std::vector<int> vecInt{ 3,8,9,6,7,10,34,57,981,301,201,701,623,82,201,2909 };

    vecInt.pop_back();

    //
    for (int i = 0; i < vecInt.size(); i++)
    {
        std::cout << "pop_back vecInt[" << i << "]=" << vecInt[i] << std::endl;
    }
    std::cout << "pop_back vecInt size: " << vecInt.size() << "capacity is :" << vecInt.capacity() << std::endl;

    //erase
    vecInt.erase(vecInt.begin() + 3);
    for (int i = 0; i < vecInt.size(); i++)
    {
        std::cout << "erase vecInt[" << i << "]=" << vecInt[i] << std::endl;
    }
    std::cout << "erase vecInt size: " << vecInt.size() << "capacity is :" << vecInt.capacity() << std::endl;

    //swap
    swap(*(std::begin(vecInt) + 1), *(std::end(vecInt) - 1));
    for (int i = 0; i < vecInt.size(); i++)
    {
        std::cout << "after swap vecInt[" << i << "]=" << vecInt[i] << std::endl;
    }
    std::cout << "after swap vecInt size: " << vecInt.size() << "capacity is :" << vecInt.capacity() << std::endl;
    vecInt.pop_back();
    
    for (int i = 0; i < vecInt.size(); i++)
    {
        std::cout << "after swap rest vecInt[" << i << "]=" << vecInt[i] << std::endl;
    }

    //erase指定范围
    vecInt.erase(vecInt.begin() + 2, vecInt.end() - 5);
    for (int i = 0; i < vecInt.size(); i++)
    {
        std::cout << "erase appoint vecInt[" << i << "]=" << vecInt[i] << std::endl;
    }

    //remove
    std::remove(vecInt.begin(), vecInt.end(), 3);
    for (int i = 0; i < vecInt.size(); i++)
    {
        std::cout << "after remove vecInt[" << i << "]=" << vecInt[i] << std::endl;
    }
    std::cout << "remove vecInt size: " << vecInt.size() << "capacity is :" << vecInt.capacity() << std::endl;

    //clear
    vecInt.clear();
    for (int i = 0; i < vecInt.size(); i++)
    {
        std::cout << "clear vecInt[" << i << "]=" << vecInt[i] << std::endl;
    }
    std::cout << "clear vecInt size: " << vecInt.size() << "capacity is :" << vecInt.capacity() << std::endl;

结果如下:
image.png
image.png
说明:
pop_back:执行后删除了最后一个元素,容器大小-1,容量不变;
erase:执行后,会返回一个指向删除元素所在位置下一个位置的迭代器,erase在删除元素时,会将删除位置后续的元素陆续前移,并将容器的大小减-1;erase也可以删除指定区域的元素,会返回指向此区域之后一个位置的迭代器;
remove:删除容器中和指定元素值相同的所有元素,在对容器执行完 remove() 函数之后,由于该函数并没有改变容器原来的大小和容量,因此借助 remove() 返回的迭代器完成正确的遍历
remove()的实现原理是:在遍历容器中的元素时,一旦遇到目标元素,就做上标记,然后继续遍历,直到找到一个非目标元素,即用此元素将最先做标记的位置覆盖掉,同时将此非目标元素所在的位置也做上标记,等待找到新的非目标元素将其覆盖。通过 remove() 函数删除掉 demo 容器中的多个指定元素,该容器的大小和容量都没有改变,其剩余位置还保留了之前存储的元素,此时可以使用erase清理无用的数据:

vecInt.erase(iter, vecInt.end());

建议:remove()用于删除容器中指定元素后,可使用 erase() 成员函数清理无用数据。
clear:清理容器中所有的元素

小菜鸟一枚,望各位大佬不吝指教,用于记录学习

1 声望
0 粉丝
0 条评论
推荐阅读
C++ STL multiset容器
multiset 类模板提供的构造函数,和 set 类模板中提供创建 set 容器的构造函数,是完全相同的。因此创建set容器的方式适用于创建multiset容器。具体的方法参考set容器:[链接]

等待樱花盛开阅读 970

麒麟操作系统 (kylinos) 从入门到精通 - 研发环境 - 第二十一篇 C++/C语言开发环境搭建
类别:笔记本型号:中国长城 NF14C硬件平台:飞腾处理器(ArmV8 指令集)系统:银河麒麟操作系统 V10 SP1(2203) 关键词:信创,麒麟系统,linux,c++,c,内核飞腾,arm

码上世界1阅读 2.4k评论 1

封面图
万字避坑指南!C++的缺陷与思考(下)
导读 | 在万字避坑指南!C++的缺陷与思考(上)一文中,微信后台开发工程师胡博豪,分享了C++的发展历史、右值引用与移动语义、类型说明符等内容,深受广大开发者喜爱!此篇,我们邀请作者继续总结其在C++开发过...

腾讯云开发者5阅读 498评论 1

DBoS 系统说明
程序员TianSong以单片机开发入门,后续又做了 Qt 相关工作,有时间后开始进行 linux 相关的学习,恰巧在二一年十一月份,百问网的韦东山老师进行了三个月的 linux 驱动直播,于是有了开发 DBoS 的念头。

TianSong1阅读 1.1k

【Qt】简单桌面
[链接]简介简单桌面是一款小巧便捷的桌面背景管理软件。由编程爱好者个人开发,不收集使用者个人信息、不连接网络、不弹窗。下载功能支持单静态图片及多静态图片轮播(轮播时间可设置)支持GIF动画背景支持视频背...

TianSong3阅读 2.1k

一种将函数模板定义和声明分开的方法
&emsp;&emsp;在 C++ 中为了操作简洁引入了函数模板。所谓的函数模板实际上是建立一个通用函数,其函数类型或形参类型不具体指定,用一个虚拟的类型来表达,这个通用函数就称为函数模板。

Sharemaker阅读 871

封面图
Workflow的JSON解析器
Workflow中有一个小而美的json-parser,一千行代码写得非常典雅精致。不仅可以学习到经典的C语言写法、递归解析的架构、与内核近似的编码风格、简洁的接口设计,而且也非常方便引入项目中作为轻量级的json解析器...

1412阅读 829

小菜鸟一枚,望各位大佬不吝指教,用于记录学习

1 声望
0 粉丝
宣传栏