容器大小的改变以及容器操作可能使迭代器失效、vector对象的容量变化
1 改变容器的大小
我们可以使用resize来增加或缩小容器,与往常一样,array不支持resize。如果当前大小大于所要求的大小,容器后面的元素会被删除;如果当前大小小于新大小,会将新元素添加到容器后部:
list<int> ilist(10,42); //10个int:每个的值都是42
ilist.resize(15); //将5个值为0的元素添加到ilist的末尾
ilist.resize(25,-1); //将10个值为-1的元素添加到ilist的末尾
ilist.resize(5); //从ilist末尾删除20个元素
resize操作接受一个可选的元素值参数,用来初始化添加到容器中的元素。如果调用者未提供此参数,新元素进行值初始化。如果容器保存的是类类型,且resize向容器添加新元素,则我们必须提供初始值,或者元素类型必须提供一个默认构造函数。
| 顺序容器大小操作 |
|
resize不适用array c.resize(n) 调整c的大小为n个元素。若n<c.size(),则多出的元素被丢弃。若必须添加新元素,对新元素进行值初始化 c.resize(n,t) 调整c的大小为n个元素。任何新添加的元素都初始化为值t 注意:如果resize缩小容器,则指向被删除元素的迭代器、引用和指针都会失效;对vector、string或deque进行resize可能导致迭代器、指针和引用失效 |
容器操作可能使迭代器失效
向容器中添加元素和从容器中删除元素的操作可能会使指向容器的指针、引用或迭代器失效。一个失效的指针、引用或迭代器将不再表示任何元素。使用失效的指针、引用或迭代器是一种严重的程序设计错误,很可能引起与使用未初始化指针一样的问题
向容器添加元素后:
- 如果容器是vector或string,且存储空间被重新分配,则指向容器的迭代器、指针和引用都会失效。如果存储空间未重新分配,指向插入位置之前的元素的迭代器、指针和引用将会失效。
- 对于deque。插入到除首尾位置之外的任何位置都会导致迭代器、指针和引用失效。如果在首尾位置添加元素,迭代器会失效,但指向存在的元素的引用和指针不会失效
- 对于list和forward_list,指向容器的迭代器(包括尾后迭代器和首前迭代器)、指针和引用仍然有效。
当我们从一个容器中删除元素后,指向被删除元素的迭代器、指针和引用会失效。当我们删除一个元素后:
- 对于list和forward_list,指向容器其他位置的迭代器、指针和引用仍然有效
- 对于deque,如果在首尾之外的任何位置删除元素,那么指向被删除元素外其他元素的迭代器、引用或指针也会失效。如果是删除deque的尾元素,则尾后迭代器也会失效,但其他迭代器、引用和指针不受影响;如果是删除首元素,这些也不会受影响。
- 对于vector和string,指向被删除元素之前元素的迭代器、引用和指针仍有效。注意:当我们删除元素时,尾后迭代器总是会失效。
编写改变容器的循环程序
添加/删除vector、string或deque元素的循环程序必须考虑迭代器、引用和指针可能失效的问题。程序必须保证每个循环步中都更新迭代器、引用和指针。如果循环中调用的是insert或erase,那么更新迭代器很容易。这些操作都返回迭代器,我们可以用来更新:
//傻瓜循环,删除偶数元素,复制每个奇数元素
vector<int> vi={,,,,,,,,,};
auto iter=vi.begin(); //调用begin而不是cbegin,因为我们要改变vi
while(iter!=vi.end())
{
if(*iter%){
iter=vi.insert(iter,*iter);//复制当前元素
iter+=; //向前移动迭代器,跳过当前元素以及插入到它之前的元素
}
else
iter=vi.erase(iter); //删除偶数元素
//不应向前移动迭代器,iter指向我们删除的元素之后的元素
}
此程序删除vector中的偶数元素,并复制每个奇数元素。我们在调用insert和erase后都更新迭代器,因为两者都会使迭代器失效。
不要保存end返回的迭代器
当我们添加/删除vector或string的元素后,或在deque中首元素之外任何位置添加/删除元素后,用来end返回的迭代器总是会失效。因此,添加或删除元素的循环程序必须反复调用end,而不能在循环之前保存end返回的迭代器,一直当作容器末尾使用。
vector对象时如何增长的
为了支持随机访问,vector将元素连续存储——每个元素紧挨着前一个元素存储。通常情况下,我们不必关心一个标准库类型是如何实现的,而只需关心它如何使用。然而,对于vector和string,其部分实现渗透到了接口中。
假定容器中元素是连续存储的,其容器的大小是可变的,考虑向vector和string中添加元素会发生什么;如果没有空间容纳新元素,容器不可能简单地将它添加到内存中其他位置——因为元素必须连续存储。容器必须分配新的内存空间来保存已有元素和新元素,将已有元素从旧位置移动到新空间中,然后添加新元素,释放就存储空间。如果我们每添加一个新元素,vector就执行一次这样的内存分配和释放操作,性能会慢到不可接受。
管理容器的成员函数
vector和string类型提供了一些成员函数,允许我们与它的实现中内存分配部分互动。capacity操作告诉我们容器在不扩张内存空间的情况下可以容纳多少个元素。reserve操作允许我们通知容器它应该准备保存多少个元素。
| 容器大小管理操作 |
|
shrink_to_fit只适用于vector、string和deque capacity和reserve只适用于vector和string c.shrink_to_fit() 请将capacity减少为size相同大小 c.capacity() 不重新分配内存空间的话,c可以保存多少元素 c.reserve(n) 分配至少能容纳n个元素的内存空间 |
reserve并不改变容器中元素的数量,它仅影响vector预先分配多大的内存空间
只有当需要的内存空间超过当前容量时,reserve调用才会改变vector的容量。如果要求大小大于当前容量,reserve至少分配与要求一样大的内存空间(可能更大)。
如果需求大小小于等于当前空间,reserve什么也不做。特别是,当需求大小小于当前容量时,容器不会退回内存空间。因此,在调用reserve之后,capacity将会大于等于传递给reserve的参数。
这样,调用reserve永远也不会减少容器占用的内存空间。类似的,resize成员函数只改变容器中元素的数目,而不是容器的容量。我们同样不能使用resize来减少容器预留的内存空间。
在新标准中,我们可以调用shrink_to_fit来要求deque、vector或string退回不需要的内存空间。此函数指出我们不再需要任何多余的内存空间。但是,具体的实现可以选择忽略此请求。也就是说,调用shrink_to_fit也并不保证一定退回内存空间。
capacity和size
容器size是指它已经保存的元素的数目;而capacity则是在不分配新的内存空间的前提下它最多可以保存多少元素。
容器大小的改变以及容器操作可能使迭代器失效、vector对象的容量变化的更多相关文章
- echarts的图表根据父容器大小的改变而改变(弹窗easy-ui的window窗口)
1.echarts的图表只绘制一次,所以要想大小随着父容器变化就得调方法重新绘制.所以把绘制图表的方法提出来. <div class="echart"> <div ...
- 顺序容器----顺序容器操作,vector对象如何增长,额外的string操作,容器适配器
一.顺序容器操作 1.向顺序容器添加元素 向顺序容器(array除外)添加元素的操作: 操作 说明 c.push_back(t) 在c的尾部创建一个值为t的元素.返回void c.emplace_ba ...
- cb11a_c++_顺序容器的操作4_容器大小操作_resize-max_size
cb11a_c++_顺序容器的操作4 2 容器大小的操作 3 c.size() 容器当前的个数 4 c.max_size(),容器最大存储量 5 c.empty() 是否为空 6 c.resize(n ...
- C++ Primer : 第九章 : 顺序容器的操作以及迭代器失效问题
顺序容器的添加.访问.删除操作以及forward_list的特殊操作,还有迭代器失效问题. 一.向容器添加元素 // array不支持这些操作 // forward_list有自己撰于的版本的inse ...
- 迭代器类vector::iterator 和 vector::reverse_iterator 的实现、迭代器类型、常用的容器成员
一.迭代器 迭代器是泛型指针 普通指针可以指向内存中的一个地址 迭代器可以指向容器中的一个位置 STL的每一个容器类模版中,都定义了一组对应的迭代器类.使用迭代器,算法函数可以访问容器中指定位置的元素 ...
- STL容器迭代器失效问题讨论
STL源码剖析---迭代器失效小结 vector迭代器的几种失效的情况: .当插入(push_back)一个元素后,end操作返回的迭代器肯定失效. .当插入(push_back)一个元素后,capa ...
- 使用 Device Mapper来改变Docker容器的大小
作者:Jérôme Petazzoni ( Docker 布道师) 译者:Mark Shao ( EMC 中国高级工程师) 如果在 CentOS . REHL . Fedor 或者其他默认没有 AUF ...
- 根据html容器大小和显示文字多少调节字体大小
在做html相关的东西的时候经常会遇到这样的问题,容器大小(长x宽)固定,容器包含内容(特指文字)多少不固定,这个时候就让人很苦恼了,将字体大小设置成多少才合适呢?下面看看我的解决思路: 首先要知道网 ...
- c/c++ 标准顺序容器 之 push_back,push_front,insert,emplace 操作
c/c++ 标准顺序容器 之 push_back,push_front,insert,emplace 操作 关键概念:向容器添加元素时,添加的是元素的拷贝,而不是对象本身.随后对容器中元素的任何改变都 ...
随机推荐
- 第四章 USB库介绍
4.1 USB库函数简介 Luminary Micro公司提供USB处理器的USB库函数,应用在Stellaris处理器上,为USB设备.USB主机.OTG开发提供USB协议框架和API函数,适用于多 ...
- Android Service 生命周期和使用注意项
一.基础知识 服务一般分为两种: 1:本地服务, Local Service 用于应用程序内部.在Service可以调用Context.startService()启动,调用Context.stopS ...
- linux设备驱动那点事儿之平台设备理论篇
一:Platform总线 1.1概述 一个现实的linux设备驱动通常需要挂接在一种总线上,对于本身依附于PCI,USB,IIC,SPI等的设备而言,这自然不是问题,但是在嵌入式系统里面,SOC系统中 ...
- APK签名原理
网上已有多篇分析签名的类似文章,但是都有一个共同的问题,就是概念混乱,混乱的一塌糊涂. 在了解APK签名原理之前,首先澄清几个概念: 消息摘要 -Message Digest 简称摘要,请看英文翻译, ...
- 加载网络映射盘中的assembly失败的处理办法
错误症状: 1.{"未能加载文件或程序集“file://*****”或它的某一个依赖项.不支持操作. (异常来自 HRESULT:0x80131515)":"file:/ ...
- 【HDOJ】1045 Fire Net
经典深搜.注意满足条件. #include <stdio.h> #include <string.h> #define MAXNUM 5 char map[MAXNUM][MA ...
- 自定义web服务器(四)
关于HTTP协议的具体内容,前面章节已经有所讲解,相信读者已有所了解,在此不在累述,本章节讲解自定义web服务器. 一,.net提供自定义Web服务器的类 以下只是写主要的类 1.HTTPListe ...
- apache开源项目--kafka
kafka是一种高吞吐量的分布式发布订阅消息系统,她有如下特性: 通过O(1)的磁盘数据结构提供消息的持久化,这种结构对于即使数以TB的消息存储也能够保持长时间的稳定性能. 高吞吐量:即使是非常普通的 ...
- js模块,类,继承,命名空间,私有属性等相关概念梳理
js确切的说是一种基于对象的语言,和纯面向对象的语言(比如as)稍微有点区别,js中没有类的概念.虽然有继承但是基于原型的继承.随着前段越来越受重视,jser们利用js的一些特性他们制造出了和纯面向对 ...
- 深入理解OAuth2.0
1. 引言 如果你开车去酒店赴宴,你经常会苦于找不到停车位而耽误很多时间.是否有好办法可以避免这个问题呢?有的,听说有一些豪车的车主就不担心这个问题.豪车一般配备两种钥匙:主钥匙和泊车钥匙.当你到酒店 ...