目录

vector杂谈

构造函数

赋值运算符重载

修改函数

1.push_back和pop_back ​​​​​​

2.assign

3.swap

4.insert

5.erase

获取元素的函数

1.operator[]和at

vector的迭代器类

常见用途(遍历,范围for)

1.begin

2.end

3.rbegin

4.rend

5.其他带c的迭代器的接口

容量相关函数

1.size

2.maxsize

3.reserve

4.resize

为什么STL中vector或者list等容器不像string一样提供find接口呢?

非成员函数重载

relational operators (vector)

说说STL中文件里的sort接口(随机存取迭代器,仿函数)

说说函数模板vector的实例化vector类和string类的区别


vector杂谈

先来看一看vector的框架,它是一个类模板。第一个模板参数就是让vector判断自己需要存储什么类型的数据,那第二个模板参数Alloc是什么呢?

它表示空间配置器,也就是常说的内存池,STL的所有容器为了提高效率,都不会直接去找堆要空间,而是向内存池要空间,只有内存池会去找堆申请空间。

可以看到Alloc是给了一个缺省值的,也就是说,如果你觉得在某些情况下库中的内存池类不好用,你可以自己写一个内存池类,然后传给模板参数Alloc。

构造函数

接下来看看默认成员函数

1.第一个是默认构造,有缺省参数,为内存池类的对象。默认构造演示如下。

2.第二个是用n个value_type填充vector。可以观察下表,size_type这个类型就是size_t,value_type这个类型就是模板参数T的值,而allocator_type这个类型就是模板参数Alloc的值。

第二个构造函数演示如下。

3.第三个是用迭代器区间构造vector,该构造函数是一个函数模板,表示可以用任意迭代器类型构造vector,如下图演示,使用了string类的迭代器构造vector<int>。 ​​​​ 

4.第四个就是拷贝构造了,库里的拷贝构造是深拷贝。如下图v3就是调用的拷贝构造。

赋值运算符重载

这边涉及深拷贝的问题,需要重新开辟空间。库中是实现了深拷贝的,后序咱们实现时该成员函数时也得深拷贝。

修改函数

1.push_back和pop_back ​​​​​​

push_back表示尾插,如下图,vector的push_back每次只能尾插一个T类型的值。

pop_back表示尾删,每次只删一个T类型的值。

2.assign

是一个给vector赋值的接口,将指定的数据赋值给vector,可能会替换vector原有的内容,并相应地修改vector的大小,如下图演示代码。

3.swap

用于交换两个vector的值,其容量大小也是会交换的,演示代码如下。

4.insert

1)第一个接口就是在迭代器指向的位置插入值val,演示如下图。

2)第二个接口就是在迭代器指向的位置插入n个val,演示如下图。

3)第三个接口是一个函数模板,表示在vector的迭代器position指向的位置插入任意类的迭代器区间【first,last)指向的值,演示如下图,104和105分别代表字符集中h和i对应的编码。

5.erase

如上图红框处所说,该接口用于要么从vector中删除单个元素,要么删除一系列元素。

1)第一个接口用于删除迭代器指向位置的元素,演示如下图。

2)第二个元素用于删除一个迭代器区间指向位置的元素,区间【first,last)左闭右开 ,演示如下图。

一般来说,erase是配合find一起使用的,如下图演示。

获取元素的函数

1.operator[]和at

用于返回下标为n的元素的引用。返回值reference就表示引用,const对象调用【】就返回const引用,普通对象调用【】就返回引用,可以认为reference等于T&。

该函数的功能和at一样,但at越界后是抛异常,而operator【】越界是暴力处理,直接assert断言错误。

有了operator【】,我们就有了第一种遍历vector的方式,如下图这种像数组一样的遍历方式,全都得益于operator【】的重载实现。

上面也说过,at和operator【】唯一的区别就是越界时抛异常,这里不再赘述。

vector的迭代器类

常见用途(遍历,范围for的傻瓜式替换)

有了迭代器,我们就可以实现第二种遍历vector的方式,如下图。

也可以通过迭代器对vector内的元素进行修改,如下图红框处。

同时因为有了迭代器,因为范围for底层就是迭代器实现的,所以vector也支持范围for,如下图演示。

如何理解范围for的底层就是通过迭代器实现的呢?

编译器会把范围for的写法自动转换成迭代器遍历的写法,将每一个迭代器解引用后的值如 *it的值都依次赋值给e,后序编译器就看不到范围for,只能看到迭代器遍历,换言之只有用户看到的是范围for,编译器看到的依然是迭代器遍历,所以范围for上层看着挺牛逼,但底层就是通过一个傻瓜式的替换实现的。

那这里为什么说是傻瓜式的呢?

因为编译器是严格按照库里迭代器的使用方法来进行转换的,比如说库里的用于返回指向首元素位置的迭代器的方法名称叫begin(),返回指向最后一个元素的后一个位置的迭代器的方法名称叫end(),那么假如你在模拟实现一个容器时,你定义的返回指向首元素位置的迭代器的方法叫Begin(),那么编译器就不认识了,即无法转换成范围for了,导致最后迭代器遍历的方式能跑,但范围for编不过,报错。

1.begin

如下图红框,begin()用于返回指向第一个元素的迭代器对象。

2.end

如下图红框past-the-end,表示vector中最后一个元素的后一个位置,所以end()用于返回指向最后一个元素的后一个位置的迭代器对象。

3.rbegin

如上图红框,rbegin接口用于返回指向最后一个元素的迭代器对象。

4.rend

如上图红框,rend()用于返回指向第一个元素的前一个位置的迭代器对象。

5.其他带c的迭代器的接口

用于返回const迭代器 ,但即使没有这些接口,使用begin或者end等接口依然可以返回const迭代器,详情请参考<<string的介绍和使用>>一文中对迭代器的讲解。

容量相关函数

1.size

如下图所示,该接口返回一个size_type类型的值,表示vector中目前存在多少有效数据。

2.maxsize

如上图红框,该接口用于返回vector中最多能存储多少个T类型的元素。演示如下图,事实上这个值就是用堆上最大可开辟的空间除以sizeof(T)。该接口没有什么意义,之后在讲解STL容器时将不再赘述。

3.reserve

如上图红框所示,当n小于当前vector的_capacity时,不会重新开辟空间,_capacity也不会变小,_size也不会变化,容器管理的元素也不会受到影响。

只有当n大于_capacity时,才会重新开辟空间,修改_capacity的值,并拷贝数据到新空间,然后释放旧空间。

4.resize

如果n小于当前容器大小,则vector中的元素将减少到只有前n个元素,会删除超出的元素(并销毁它们)。如下图演示,先resize到1,再resize到3,此时后两个元素已经被销毁了。

如果n大于当前容器大小,则会在vector的末尾不断插入元素来扩展vector,直到达到n的大小,如果指定了val,则将新插入的元素初始化为val,否则使用缺省值,也就是T()对新插入的元素进行初始化。

如果n也大于当前容器容量,则自动重新分配新的存储空间,然后拷贝旧数据到新空间,然后在vector的末尾不断插入元素来扩展vector,直到达到n的大小,元素的值为value_type类的对象的值。

为什么STL中vector或者list等容器不像string一样提供find接口呢?

因为vector和list它们的find接口是可以实现成通用的接口的,都可以通过一段迭代器区间来寻找指定的值,所以没必要为vector和list等容器再分别单独设计一个find接口。如下图,当vector或者list需要查找指定元素时,可以通过调用头文件<algorithm>中的find接口完成需求。

而string类和它们不太一样,因为在string中查找时,可能找一个字符,可能找一个字串,找到后返回下标。因为string的查找具有多样性,从而导致了string的查找比较独特,所以STL认为有必要单独为string实现一个find接口。

分割线---------------

既然提到了algorithm中的find,就来介绍一下吧。

find是一个函数模板,所以可以让vector或者list这些不同的容器通用。

在迭代器区间 [first,last)中寻找第一个值等于val的元素,注意这里是左闭右开,不包括last迭代器指向的元素。如果找不到值等于value的元素,函数将返回last迭代器,如果找到了则返回元素对应的迭代器。

函数内部逻辑为使用运算符==将每个元素与val的值进行比较,如上图红框处代码所示。

接下来是演示

上图和下图就可以证明,当find找不到和value值相等的元素时,会返回last迭代器。

分割线-----------------

如下图,因为end迭代器指向vector最后一个元素的后一个位置,所以这里是能够找到5的。

定义一个迭代器对象一般比较繁琐,这时就可以使用auto,如下图。

非成员函数重载

relational operators (vector)

不常用,了解即可。

如上图所示,vector也是支持比较大小的,比较逻辑和string字符串比较大小的方式一致,演示图如下。

说说STL中<algorithm>文件里的sort接口(随机存取迭代器,仿函数)

STL里的sort接口也是一个函数模板,第一个模板参数为随机存取迭代器,表示sort接口只支持排序可以通过随机存取迭代器遍历的类,比如vector或者deque这样的物理空间连续的类,第二个接口还有第二个模板参数,为比较方式类,表示排序时按照什么依据进行排序,一般是传仿函数进去,默认提供的comp只支持排升序。

sort底层就是快排,库中对快排的一些优化比如三数取中也是实现了的。

关于随机存取迭代器是什么可以通过下图了解。

sort使用示范如下图。

那我想要排降序该怎么办呢?如下图,给sort的第二个接口的第二个参数传下图的greater<int>的对象,后面在<<priority_queue的模拟实现>>一文中学了仿函数后,就会知道greater等价于>,这里记忆greater排降序有一个巧妙的办法,因为greater等价于>,所以现在首先记住>的开口方向,然后随意加上几个字母,比如x、y、z,最后将前两步组合就是x>y>z,嘿嘿,这不就是降序吗。

实际上sort默认排升序是因为默认传给comp的值为less<int>类型的对象,如下图所示,后面在<<priority_queue的模拟实现>>一文中学了仿函数后,我们就能知道less<T>等价于<。这里记忆less排升序有一个巧妙的办法,因为less等价于<,所以现在首先记住<的开口方向,然后随意加上几个字母,比如x,y,z,最后将前两步组合就是x<y<z,这不就是升序吗。

如果觉得给less<int>对象取名字麻烦,也可以直接传匿名对象,如下图所示。

说说函数模板vector的实例化vector<char>类和string类的区别

1)vector<char>类型管理数据的指针指向的空间里默认是不存在\0的。

2)vector<char>不存在+=、findC语言字符串、to_string、>>、<<等等操作。

所以vector<char>是无法替代string的,所以实际中一般是不会使用vector<char>类生成对象的,因为用它不如直接用各方面都更优秀的string类,所以函数模板vector主要用于生成除char类的其他类的实例化,如vector<int>或者vector<double>等等。但有些地方可能会将两个类组合起来用,比如vector<string>。

如上图是几种不同的插入方法, strV是vector<string>类的对象,第三行和第四行本质是相同的方法,因为string支持const char*的构造函数,而该构造函数是单参的,并且没有用explicit修饰,所以支持隐式类型转换。第四行就是利用“王六”这个const char*的数据构造一个匿名的string对象,然后将这个匿名对象引用给如下图的const value_type类的val对象,这里没有发生拷贝构造。

第三行和第四行push_back的流程是一模一样的,只不过第三行没有隐式转换。

vector的介绍与使用相关推荐

  1. STL vector用法介绍

    STL vector用法介绍 介绍 这篇文章的目的是为了介绍std::vector,如何恰当地使用它们的成员函数等操作.本文中还讨论了条件函数和函数指针在迭代算法中使用,如在remove_if()和f ...

  2. STL vector 容器介绍 (转载)

    STL vector 容器介绍<?xml:namespace prefix = o /> A Presentation of the STL Vector Container (By Ni ...

  3. STL vector 容器介绍

    介绍 这篇文章的目的是为了介绍std::vector,如何恰当地使用它们的成员函数等操作.本文中还讨论了条件函数和函数指针在迭代算法中使用,如在remove_if()和for_each()中的使用.通 ...

  4. STL vector 用法介绍

    介绍 这篇文章的目的是为了介绍std::vector,如何恰当地使用它们的成员函数等操作.本文中还讨论了条件函数和函数指针在迭代算法中使用,如在remove_if()和for_each()中的使用.通 ...

  5. C++语言vector容器介绍和示例

    之前我们在声明数组的时候,采用的是datatype  array[len]的形式,数组在分配之后,不能调整大小,删除和插入数据时操作十分的繁琐,虽然可以采用链表,但是链表的操作更麻烦,我喜欢简单的方法 ...

  6. c++ std vector用法介绍

    c++ vector 一部分内容来自:http://blog.csdn.net/phoebin/article/details/3864590:http://www.cnblogs.com/wang7 ...

  7. 吊打面试官:Vector详细介绍(源码解析)和使用示例

    概要 学完ArrayList和LinkedList之后,我们接着学习Vector.学习方式还是和之前一样,先对Vector有个整体认识,然后再学习它的源码:最后再通过实例来学会使用它. 第1部分 Ve ...

  8. vector容器介绍

    Vector概念 vector是将元素置于一个动态数组中加以管理的容器. vector可以随机存取元素(支持索引值直接存取, 用[]操作符或at()方法). vector尾部添加或移除元素非常快速,但 ...

  9. C++ stl vector介绍

    转自: STL vector用法介绍 介绍 这篇文章的目的是为了介绍std::vector,如何恰当地使用它们的成员函数等操作.本文中还讨论了条件函数和函数指针在迭代算法中使用,如在remove_if ...

最新文章

  1. 用指针和函数的方法完成两个数的交换
  2. 柱状图、堆叠柱状图、瀑布图有什么区别?怎样用Python绘制?(附代码)
  3. 整理一点关于Lucene的学习资料, 方便自己与别人查看
  4. Android之创建简单的ProgressDialog
  5. filebeat向kafka传输数据,无数据现象
  6. oracle 制定定时任务
  7. Mybatis-04-结果集映射resultMap/动态SQL/关联查询
  8. 三星 android截屏快捷键是什么手机,三星手机如何快速截屏?两种快速截图方法教给你!...
  9. excel中查找两列数据中的重复数据
  10. python自然语言学习之处理原始文本中3.1访问2554文本《罪与罚》出现问题解决
  11. 吐血整理C++书单,萌新到大牛,要看哪些书?
  12. 解决windows 10桌面文件图标上出现两个蓝色箭头
  13. 【夜读】让自己更幸福的8件小事
  14. 【程序源代码】电商网站系统
  15. linux下怎么安装打印驱动安装驱动程序,Linux下安装HP打印机的驱动程序
  16. 时间是6G研发成功的关键
  17. ViewPager的setOnPageChangeListener方法详解
  18. 行为金融(三):期望效用理论与前景理论
  19. 软键盘输入设计(C语言)
  20. STM8L自带bootloader使用教程(即使用Boot ROM升级)

热门文章

  1. 第一次原型分享——墨刀之底部导航栏
  2. 【实战篇:粘连物体分割——利用几何分割实现瓶盖分割检测】
  3. F-Measure MCC ROC Area PRC Area_MCC学生会 | 媒体运营部——若有人给你一盏灯 我给你月亮...
  4. 图解Java设计模式学习笔记——结构型模式(适配器模式、桥接模式、装饰者模式、组合模式、外观模式、享元模式、代理模式)
  5. erp实施入门完整流程
  6. BUAA全排列数的生成
  7. 惠普服务器系统管理 密码,惠普服务器 DL380 Gen9 server2012R2 登录密码找回全过程...
  8. Schillace 定律 背后的 Sam Schillace
  9. SOLIDWORKS如何快速生成材料明细表
  10. 没有core文件时定位segfault at 0 ip (null) 的问题(三):艰难定位,多种原因