• 为了支持快速随机访问,vector将元素连续存储,每个元素紧挨着前一个元素存储。通常情况下,我们不必关心一个标准库类型是如何实现的,而只需关心它如何使用。然而,对于vector和string,其部分实现渗透到了接口中。
  • 假定容器中元素是连续存储的,且容器的大小是可变的,考虑向vector或string中添加元素会发生什么:如果没有空间容纳新元素,容器不可能简单地将它添加到内存中其他位置--因为元素必须连续存储。容器必须分配新的内存空间来保存已有元素和新元素,将已有元素从旧位置移动到新空间中,然后添加新元素,释放旧存储空间。如果我们每添加一个新元素,vector就执行一次这样的内存分配和释放操作,性能会慢到不可接受。为了避免这种代价,标准库实现者采用了可以减少容器空间重新分配次数的策略。当不得不获取新的内存空间时,vector和string的实现通常会分配比新的空间需求更大的内存空间。容器预留这些空间作为备用,可用来保存更多的新元素(提前分配更大的空间)。这样,就不需要每次添加新元素都重新分配容器的内存空间了。这种分配策略比每次添加新元素时都重新分配容器内存空间的策略要高效得多。其实际性能也表现得足够好--虽然vector在每次重新分配内存空间时都要移动所有元素,但使用此策略后,其扩张操作通常比list和deque还要快。

管理容量的成员函数

  • 如表9.10所示,vector和string类型提供了一些成员函数,允许我们与它的实现中内存分配部分互动。capacity操作告诉我们容器在不扩张内存空间的情况下可以容纳多少个元素。reserve操作允许我们通知容器它应该准备保存多少个元素。

  • 有当需要的内存空间超过当前容量时,reserve调用才会改变vector的容量。如果需求大小大于当前容量,reserve至少分配与需求一样大的内存空间(可能更大)。如果需求大小小于或等于当前容量,reserve什么也不做。特别是,当需求大小小于当前容量时,容器不会退回内存空间。因此,在调用reserve之后,capacity将会大于或等于传递给reserve的参数。这样,调用reserve永远也不会减少容器占用的内存空间。类似的,resize成员函数(参见9.3.5节,第314页)只改变容器中元素的数目,而不是容器的容量。我们同样不能使用resize来减少容器预留的内存空间。
  • 在新标准库中,我们可以调用shrink_to_fit来要求deque、vector或string退回不需要的内存空间。此函数指出我们不再需要任何多余的内存空间。但是,具体的实现可以选择忽略此请求。也就是说,调用shrink_to_fit也并不保证一定退回内存空间。

capacity和size

  • 理解capacity和size的区别非常重要。容器的size是指它已经保存的元素的数目;而capacity则是在不分配新的内存空间的前提下它最多可以保存多少元素。下面的代码展示了size和capacity之间的相互作用
vector<int> ivec;
//size 应该为0 capacity应该依赖于具体实现
cout << "ivec:size: " <<ivec.size()<< "capacity: "  <<ivec.capacity() << endl;
//向ivec 添加24个元素
for(vector<int>::size_type ix = 0; ix != 24; ix++){ivec.push_back(ix);
}
//size 应该为24 capacity应该大于等于24 具体依赖于标准库的实现
cout << "ivec:size: " <<ivec.size()<< "capacity: "  <<ivec.capacity() << endl;
  • 当在我们的系统上运行时,这段程序得到如下输出:
  • ivec:size:0 capacity:0
  • ivec:size:24 capacity:32
  • 我们知道一个空vector的size为0,显然在我们的标准库实现中一个空vector的capacity也为0。当向vector中添加元素时,我们知道size与添加的元素数目相等。而capacity至少与size一样大,具体会分配多少额外空间则视标准库具体实现而定。在我们的标准库实现中,每次添加1个元素,共添加24个元素,会使capacity变为32。可以想象ivec的当前状态如下图所示:

  • 现在可以预先分配一些额外的空间
  • ivec.reserve(50);//将capacity的容量设置至少为50 可能会更大
  • size的大小应该为24,capacity的大小应该大于等于50 具体依赖于标准库的实现
  • 添加元素用光预留空间 while(ivec.size() != ivec.capacity()){ ivec.push_back(0);}
  • 只要使用的空间没有超过vector的容量,就不需要为此重新分配空间
  • 使用shrink_to_fit将vector超出当前大小的多余内存空间退回给系统
  • ivec.shrink_to_fit(); 要求归还内存。这仅仅是一个请求,是否归还并无保证
  • 每个vector实现都可以选择自己的内存分配策略。但是必须遵守的一条原则 ,是 :只有当迫不得已时才可以分配新的内存空间
  • 只有在执行insert操作时size与capacity相等,或者调用resize或reserve时给定的大小超过当前capacity,vector才可能重新分配内存空间。会分配多少超过给定容量的额外空间,取决于具体实现。
  • 虽然不同的实现可以采用不同的分配策略,但所有实现都应遵循一个原则:确保用push_back向vector添加元素的操作有高效率。从技术角度说,就是通过在一个初始为空的vector上调用n次push_back来创建一个n个元素的vector,所花费的时间不能超过n的常数倍

C++primer第九章 顺序容器 9.4 vector对象是如何增长的相关推荐

  1. C++ Primer 第九章 顺序容器

    由于书籍上写的已经很经典了,故大部分用图片的形式来阐述概念,代码纯手打进行验证. 1.顺序容器类型:vector.deque.list.forword_list.array.string. 2.顺序容 ...

  2. C++primer第九章 顺序容器 9.6 容器适配器

    9.6容器适配器 除了顺序容器外,标准库还定义了三个顺序容器适配器:stack.queue和priority_queue 适配器(adaptor)是标准库中的一个通用概念.容器.迭代器和函数<3 ...

  3. C++primer第九章 顺序容器 9.5 额外的string操作

    除了顺序容器共同的操作之外,string类型还提供了一些额外的操作.这些操作中 的大部分要么是提供string类和C 风格字符数组之间的相互转换,要么是增加了允许我们用下标代替迭代器的版本. 标准库s ...

  4. C++primer第九章 顺序容器 9.3 顺序容器操作

    9.3顺序容器操作 顺序容器和关联容器的不同之处在于两者组织元素的方式.这些不同之处直接关系到了元素如何存储.访问.添加以及删除.上一节介绍了所有容器都支持的操作(罗列于表9.2(第295页)).本章 ...

  5. C++primer第九章 顺序容器 9.1 顺序容器概述 9.2容器库概览

    一个容器就是一些特定类型对象的集合.顺序容器(sequentialcontainer)为程序员提供了控制元素存储和访问顺序的能力.这种顺序不依赖于元素的值,而是与元素加入容器 时的位置相对应.与之相对 ...

  6. 《C++ Primer中文版(第五版)》 第九章 顺序容器

    <C++ Primer中文版(第五版)> 第九章 顺序容器 元素在顺序容器中的顺序与其加入容器时的位置相对应.关联容器中元素的位置由元素相关联的关键字值决定. 所有容器都共享公共的接口,不 ...

  7. 《C++Primer》第九章-顺序容器-学习笔记(1)-顺序容器定义与操作

    <C++Primer>第九章-顺序容器-学习笔记(1) 文章目录 <C++Primer>第九章-顺序容器-学习笔记(1) 摘要 顺序容器的定义 容器元素的初始化 将一个容器初始 ...

  8. C++primer十万字笔记 第九章 顺序容器

    顺序容器   容器就是特定类型对象的集合,顺序容器为程序员提供了控制元素存储和访问顺序的能力.这种顺序不依赖于元素的值,而是与元素加入容器时的位置相对应.标准库提供了三种容器类型. 顺序容器概述  标 ...

  9. C++ Primer 第9章 顺序容器 第一次学习笔记

    1. 顺序容器概述 #include <vector> //可变大小数组.支持快速随机访问.在尾部之外的位置插入或删除元素可能很慢 #include <deque> //双端队 ...

最新文章

  1. keepalived+nginx安装与配置
  2. JavaScript多线程之HTML5 Web Worker
  3. api 和 C# 里的接口的区别?
  4. Fabric 链码Chaincode 的安装、初始化、调用、升级
  5. MapReduce既是编程模型又是计算框架
  6. 苹果面临5G困境!向三星采购碰壁 高通表态:苹果有我们电话
  7. php默认站点,PHP学习之Apache修改默认站点的目录
  8. linux 脚本 日志文件,在linux下用脚本输出日志
  9. 基于javaweb房屋租赁系统设计与实现
  10. Struts 2教程
  11. vue实现倒计时60秒
  12. 阴历阳历相互转换c代码
  13. 阻尼牛顿法_python
  14. Matlab中如何清除persistent 变量
  15. 使用stp制造广播风暴!
  16. 及其他公共信息网络的计算机上存储,不得在未采取防护措施的情况下将互联网及其他公共信息网络上的数据复制到涉密计算机及网络,确...
  17. 没项目实战经验?分享自学练手的软件测试项目实战+数据库+接口,部署超级简单
  18. 使用vba操作工作表,实现报表汇总
  19. 机器学习中SVM的损失函数,向量积
  20. 怎样解决PHP中文乱码问题

热门文章

  1. python中回车怎么表示_如何在python中使用读取行仅拆分回车符?
  2. 第七节:利用CancellationTokenSource实现任务取消和利用CancellationToken类检测取消异常。
  3. 第七节:框架搭建之页面静态化的剖析
  4. mysql查询后从高到低排序_[MySQL基础]三、排序查询
  5. linux 性能测试iostat,Linux性能分析之二(iostat)
  6. 查看linux硬核上的线程,给大家分享一点基础硬核知识哦 Linux的基础指令操作Lin...
  7. 【POJ - 2186】Popular Cows (Tarjan缩点)
  8. 【蓝桥杯官网试题 - 算法训练 】P0502(乱搞,tricks)
  9. 【POJ - 1511】 Invitation Cards(Dijkstra + 反向建图 多源到单源最短路的处理)
  10. Apollo自动驾驶入门课程第⑩讲 — 控制(下)