vector的介绍与使用
目录
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的介绍与使用相关推荐
- STL vector用法介绍
STL vector用法介绍 介绍 这篇文章的目的是为了介绍std::vector,如何恰当地使用它们的成员函数等操作.本文中还讨论了条件函数和函数指针在迭代算法中使用,如在remove_if()和f ...
- STL vector 容器介绍 (转载)
STL vector 容器介绍<?xml:namespace prefix = o /> A Presentation of the STL Vector Container (By Ni ...
- STL vector 容器介绍
介绍 这篇文章的目的是为了介绍std::vector,如何恰当地使用它们的成员函数等操作.本文中还讨论了条件函数和函数指针在迭代算法中使用,如在remove_if()和for_each()中的使用.通 ...
- STL vector 用法介绍
介绍 这篇文章的目的是为了介绍std::vector,如何恰当地使用它们的成员函数等操作.本文中还讨论了条件函数和函数指针在迭代算法中使用,如在remove_if()和for_each()中的使用.通 ...
- C++语言vector容器介绍和示例
之前我们在声明数组的时候,采用的是datatype array[len]的形式,数组在分配之后,不能调整大小,删除和插入数据时操作十分的繁琐,虽然可以采用链表,但是链表的操作更麻烦,我喜欢简单的方法 ...
- c++ std vector用法介绍
c++ vector 一部分内容来自:http://blog.csdn.net/phoebin/article/details/3864590:http://www.cnblogs.com/wang7 ...
- 吊打面试官:Vector详细介绍(源码解析)和使用示例
概要 学完ArrayList和LinkedList之后,我们接着学习Vector.学习方式还是和之前一样,先对Vector有个整体认识,然后再学习它的源码:最后再通过实例来学会使用它. 第1部分 Ve ...
- vector容器介绍
Vector概念 vector是将元素置于一个动态数组中加以管理的容器. vector可以随机存取元素(支持索引值直接存取, 用[]操作符或at()方法). vector尾部添加或移除元素非常快速,但 ...
- C++ stl vector介绍
转自: STL vector用法介绍 介绍 这篇文章的目的是为了介绍std::vector,如何恰当地使用它们的成员函数等操作.本文中还讨论了条件函数和函数指针在迭代算法中使用,如在remove_if ...
最新文章
- 用指针和函数的方法完成两个数的交换
- 柱状图、堆叠柱状图、瀑布图有什么区别?怎样用Python绘制?(附代码)
- 整理一点关于Lucene的学习资料, 方便自己与别人查看
- Android之创建简单的ProgressDialog
- filebeat向kafka传输数据,无数据现象
- oracle 制定定时任务
- Mybatis-04-结果集映射resultMap/动态SQL/关联查询
- 三星 android截屏快捷键是什么手机,三星手机如何快速截屏?两种快速截图方法教给你!...
- excel中查找两列数据中的重复数据
- python自然语言学习之处理原始文本中3.1访问2554文本《罪与罚》出现问题解决
- 吐血整理C++书单,萌新到大牛,要看哪些书?
- 解决windows 10桌面文件图标上出现两个蓝色箭头
- 【夜读】让自己更幸福的8件小事
- 【程序源代码】电商网站系统
- linux下怎么安装打印驱动安装驱动程序,Linux下安装HP打印机的驱动程序
- 时间是6G研发成功的关键
- ViewPager的setOnPageChangeListener方法详解
- 行为金融(三):期望效用理论与前景理论
- 软键盘输入设计(C语言)
- STM8L自带bootloader使用教程(即使用Boot ROM升级)
热门文章
- 第一次原型分享——墨刀之底部导航栏
- 【实战篇:粘连物体分割——利用几何分割实现瓶盖分割检测】
- F-Measure MCC ROC Area PRC Area_MCC学生会 | 媒体运营部——若有人给你一盏灯 我给你月亮...
- 图解Java设计模式学习笔记——结构型模式(适配器模式、桥接模式、装饰者模式、组合模式、外观模式、享元模式、代理模式)
- erp实施入门完整流程
- BUAA全排列数的生成
- 惠普服务器系统管理 密码,惠普服务器 DL380 Gen9 server2012R2 登录密码找回全过程...
- Schillace 定律 背后的 Sam Schillace
- SOLIDWORKS如何快速生成材料明细表
- 没有core文件时定位segfault at 0 ip (null) 的问题(三):艰难定位,多种原因