【C++】迭代器 && vector中迭代器失效

2023-11-19

1、什么是迭代器?

在STL中,容器的迭代器(Iterator)被作为容器元素对象或者IO流中的对象位置指示器.

因此,我们可以把迭代器理解为面向对象的指针(一种泛型指针通用指针),它不依赖元素的真实类型。

如何理解这里的通用

迭代器的“通用”是概念上的一种通用。所有的泛型容器和泛型算法都是用“迭代器”来指示元素对象。所有的迭代器都具有相同或相似的访问接口,但是每一种容器都有他自己的迭代器类型,毕竟每一种容器的底层存储结构不尽相同,所以迭代器的实现方式就不同。

因此,并不是存在一种“通用的迭代器”,让他可以应用于任何类型的容器

简而言之,迭代器是为了降低容器和泛型算法之间的耦合性而设计的,泛型算法的参数不是容器,而是迭代器。迭代器的概念图如下所示:
在这里插入图片描述
可以看到,容器迭代器的作用类似于数据库中的游标(cursor),它屏蔽了底层存储空间的不连续性,在上层使容器元素维持一种”逻辑连续“的假象。

2、迭代器与指针

迭代器只是在某些操作上与我们学过的指针有些类似,但是迭代器并不是指针。

指针代表真正的内存地址,即对象在内存中的存储位置

迭代器则代表元素在容器中的相对位置。

3、迭代器的分类

3.1具体分类

主要分为5类,具体如下表:
在这里插入图片描述
对于上述的这5中迭代器,他们的能力大小关系如下:
在这里插入图片描述
因此,这些迭代器必然存在以下关系:

随机访问迭代器是一种双向迭代器

双向迭代器使一种 前进迭代器

前进迭代器是一种输入迭代器

上述的关系是可以传递的

对于完全连续的容器(例如vector),没有必要重新定义迭代器类型,其元素的职责和你就可以完全直接充当迭代器。
vector::iterator 和const_iterator一般定义如下:

typedef T* iterator;
typedef const T* const_iterator;

对于不连续存储或以其他方式存储的容器,例如list等,需要自己定义定义迭代器类(class),一般情况下他们是对元素指针的封装,即模拟指针。

注意:一些特殊容器如vector和bitset等,由于他们的存储单位为bit而不是Byte,因此无法直接使用元素指针或封装来定义他们的迭代器。如果想要保持上层接口与普通容器一致,就必须做特殊处理。

清楚一些常用的容器的迭代器类别

vector的迭代器为随机访问迭代器
list的迭代器是双向迭代器
slist的迭代器是前进迭代器
deque的迭代器是随机访问迭代器
set/map的迭代器是双向迭代器

3.2为什么要对迭代器分类?

主要是泛型算法可以根据不同类别的迭代器具有不同的能力来实现不同性能的版本,使得能力大的迭代器用于这些算法时具有更高的效率。

连续存储的容器,其元素的位置指示器有两种:下标迭代器

下标的类型为unsigned int(size_t),有效范围为0 ~ (size_t)-1
迭代器的有效范围是begin() ~ end()

这类容器的接口中都会提供相应的两种元素访问方法,典型的就是string和vector,他们都支持begin(),end(),operator[]等操作

3.3迭代器的使用建议

1、尽量使用迭代器类型,而不是显式地使用指针。
2、只使用迭代器提供的标准操作,不使用任何非标准操作,以避免STL版本更新的时候出现不兼容的问题
3、当不会改动容器中的元素值的时候,使用const迭代器(const_iterator)

4、vector迭代器失效

4.1迭代器失效及其危害

迭代器失效是指当容器底层存储发生变动时,原来指向容器中某个或某些元素的迭代器由于元素存储位置发生了改变而不再指向他们,从而成为无效的迭代器。
图示:
在这里插入图片描述

4.2哪些操作会导致迭代器失效 && 如何解决

引起迭代器失效的主要操作有:
改变容器容量的方法:reserve()、resize()、push_back()、pop_back()、insert()、erase()、clear()
一些泛型算法:sort()、 copy() 、replace()、 remove()、 unipue()
集合操作算法等
下面通过两个示例说明问题:
示例一:push_back()接口

int main()
{
	vector<int> ages;
	ages.push_back(20);

	vector<int>::const_iterator iter = ages.begin();
	for (int i = 0; i < 10; i++)
	{
		ages.push_back(21);//引起若干次内存重分配操作
	}
	
	//此时访问的迭代器iter已经失效!
	cout << "The first age:" << *iter << endl;
	return 0;
}

在VS2013环境下
在这里插入图片描述

在Linux环境下
在这里插入图片描述
由于Windows和Linux平台使用的STL版本不一样,因此在对迭代器失效方面的处理方式也会有所不同。

可以看出,Windows的P.J.版本检测更加严格,而Linux的SGI版本相对宽松。

当然,从结果来看,也能够表述出迭代器失效的问题。对于严重越界的情况,Linux也会报出 Segmentation fault的错误(类比数组访问越界理解)

解决办法:
①在调用上述操作后重新获取迭代器

int main()
{
	vector<int> ages;
	ages.push_back(20);

	vector<int>::const_iterator iter = ages.begin();
	for (int i = 0; i < 10; i++)
	{
		ages.push_back(21);//引起若干次内存重分配操作
	}
	iter = ages.begin();//重新获取迭代器
	cout << "The first age:" << *iter << endl;

	return 0;
}

②在修改容器前为其预留足够的空间空间以避免存储空间重新分配
例如可以使用reserve接口来预留空间或者调整他们的大小

示例2:erase接口

int main()
{
	vector<int> v{ 1, 2, 3, 4, 5 };

	//找到并删除非末尾元素
	//vector<int>::iterator iter = find(v.begin(), v.end(),3);

	//找到并删除末尾元素
	vector<int>::iterator iter = find(v.begin(), v.end(), 5);
	v.erase(iter);

	cout << *iter << endl;
	return 0;
}

VS2013环境下
在这里插入图片描述

Linux环境下
在这里插入图片描述

由于erase的返回值时被删除元素的下一个位置,所以会存在一种情况:删除末尾元素,这样该函数的返回值就是end()的位置,鉴于这种情况,vs直接认为在执行erase后,没更新迭代器就使用的属于是非法行为。

如何解决?
删除非末尾元素:使用语句iter = v.erase(iter)在删除元素的同时更新迭代器
在这里插入图片描述

删除末尾元素:此时erase返回的时end()的位置,因此要想继续使用该迭代器,应该重新为其赋值为合法位置

在这里插入图片描述
以上就是对迭代器的简单理解和vector迭代器失效情况及处理方式的总结!

下篇带来vector容器的模拟实现~ 感觉有所帮助的读友们多多评论交流呀~
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【C++】迭代器 && vector中迭代器失效 的相关文章

  • 从 Invoke 方法获取 RETURN

    我正在尝试从另一个线程上的列表框项目中读取值 我尝试创建一种新方法来运行调用命令 我可以设法将命令发送到列表框 例如通过调用方法添加 但我似乎无法得到响应 我似乎无法获取该项目的值 我尝试了几种方法 一旦我将它从空变为字符串 事情就开始变得
  • 当其源是 https uri 时如何使 wpf MediaElement 播放

    在 wpf 独立应用程序 exe 中 我在主窗口中包含了 MediaElement
  • 通过 SOAP 的 Gmt php 或 UTC C# 等效项

    is C DateTime UtcNow和 PHPdate c 是等价的 我怀疑 因为当我肥皂时 我得到了 C
  • 以下 PLINQ 代码没有改进

    我没有看到使用以下代码的处理速度有任何改进 IEnumerable
  • 如何调试在发布版本中优化的变量

    我用的是VS2010 我的调试版本工作正常 但我的发布版本不断崩溃 因此 在发布版本模式下 我右键单击该项目 选择 调试 然后选择 启动新实例 此时我看到我声明的一个数组 int ma 4 1 2 8 4 永远不会被初始化 关于可能发生的事
  • make_shared<>() 中的 WKWYL 优化是否会给某些多线程应用程序带来惩罚?

    前几天我偶然看到这个非常有趣的演示 http channel9 msdn com Events GoingNative GoingNative 2012 STL11 Magic Secrets作者 Stephan T Lavavej 其中提
  • 关闭整数的最右边设置位

    我只需要关闭最右边的设置位即可 我的方法是找到最右边位的位置 然后离开该位 我编写这段代码是为了这样做 int POS int n int p 0 while n if n 2 0 p else break n n 2 return p i
  • 如何增加ofstream的缓冲区大小

    我想增加 C 程序的缓冲区大小 以便它不会过于频繁地写入 默认缓冲区是 8192 字节 我尝试使用 pubsetbuf 将其增加到 200K 原始代码 ofstream fq fastq1 cstr ios out fastq1 is a
  • 将 2 个字节转换为整数

    我收到一个 2 个字节的端口号 最低有效字节在前 我想将其转换为整数 以便我可以使用它 我做了这个 char buf 2 Where the received bytes are char port 2 port 0 buf 1 port
  • 在 C++ 代码 gdb 中回溯指针

    我在运行 C 应用程序时遇到段错误 在 gdb 中 它显示我的一个指针位置已损坏 但我在应用程序期间创建了 10 万个这样的对象指针 我怎样才能看到导致崩溃的一个 我可以在 bt 命令中执行任何操作来查看该指针的生命周期吗 谢谢 鲁奇 据我
  • WinForms - 加载表单时如何使用 PaintEventArgs 运行函数?

    我试图理解图形 在 Graphics FromImage 文档中 它有这样的示例 private void FromImageImage PaintEventArgs e Create image Image imageFile Image
  • 在 mvc4 中创建通用 mvc 视图

    我以前也提过类似的问题 没有得到答案 如何创建一个通用的 mvc4 视图 该视图可以显示传递给它的模型列表或单个模型 模型可以是个人 组织或团体 无论传递给它的是什么 如果您正在寻找类似的东西 model MyViewModel
  • C++ 模板可以提供 N 个给定类的公共父类吗?

    我正在寻找一个 C 模板 它可以找到一组给定类的共同父级 例如 class Animal class Mammal public Animal class Fish public Animal class Cat public Mammal
  • 如何调用与现有方法同名的扩展方法? [复制]

    这个问题在这里已经有答案了 我有这样的代码 public class TestA public string ColA get set public string ColB get set public string ColC get se
  • 时间:2019-03-17 标签:c#TimerStopConfusion

    我想通过单击按钮时更改文本颜色来将文本框文本设置为 闪烁 我可以让文本按照我想要的方式闪烁 但我希望它在闪烁几次后停止 我不知道如何在计时器触发几次后让它停止 这是我的代码 public Form1 InitializeComponent
  • 与 Entity Framework Core 2.0 的一对零关系

    我正在使用 C 和 NET Framework 4 7 将 Entity Framework 6 1 3 Code First 库迁移到 Entity Framework Core 我一直在用 Google 搜索 Entity Framew
  • 在二进制数据文件的标头中放入什么

    我有一个模拟 可以读取我们创建的大型二进制数据文件 10 到 100 GB 出于速度原因 我们使用二进制 这些文件依赖于系统 是从我们运行的每个系统上的文本文件转换而来的 所以我不关心可移植性 当前的文件是 POD 结构的许多实例 使用 f
  • 值和类型的简洁双向静态 1:1 映射

    我将从我想象如何使用我想要创建的代码开始 它不必完全像这样 但它是我在标题中所说的 简洁 的一个很好的例子 就我而言 它是将类型映射到相关的枚举值 struct bar foo
  • MSVC编译器下使用最大成员初始化联合

    我正在尝试初始化一个LARGE INTEGER在 C 库中为 0 确切地说是 C 03 以前 初始化是 static LARGE INTEGER freq 0 在 MinGW 下它产生了一个警告 缺少成员 LARGE INTEGER Hig
  • 如何知道 HTTP 请求标头值是否存在

    我确信这很简单 但是却让我感到厌烦 我在 Web 应用程序中使用了一个组件 它在 Web 请求期间通过添加标头 XYZComponent true 来标识自身 我遇到的问题是 如何在视图中检查此组件 以下内容不起作用 if Request

随机推荐

  • 简易DOCKER/K8S使用心得

    1 DOCKER安装 1 1 前置环境 首先 如果使用CentOS 你至少需要7 4以上 从内核角度来说 建议使用8 2及以上 如果是7 4以下的版本 可以通过设置仓库到7 4以上版本 再 yum install centos releas
  • 计算机内存数值存储方式-原码、反码、补码、数值溢出

    计算机内存数值存储方式 1 原码 一个数的原码 原始的二进制码 有如下特点 最高位做为符号位 0表示正 为1表示负 其它数值部分就是数值本身绝对值的二进制数 负数的原码是在其绝对值的基础上 最高位变为1 下面数值以1字节的大小描述 原码表示
  • 手把手教你实现一个向量

    文章目录 什么是向量 向量提供哪些接口 实现 宏定义 定义类 成员变量 构造函数与析构函数 构造函数 析构函数 成员函数 size get r put r e expand insert r e remove lo hi remove r
  • nodejs获取时间戳

    可以使用 JavaScript 内置的 Date 对象来获取当前的时间戳 可以使用 Date now 方法来获取当前的时间戳 consttimestamp Date now console log timestamp 也可以使用 Date
  • 轻松掌握Python自动化工具,解锁PyAutoGUI的强大功能

    前言 PyAutoGUI是一个用于图像识别和鼠标 键盘控制的Python库 它提供了一组函数和方法 用于自动化屏幕上的鼠标移动 点击 拖拽和键盘输入 以及执行图像识别和处理 本文旨在帮助读者入门 PyAutoGUI 理解其基础概念和掌握最佳
  • js逆向-国密SM2初探

    目录 前言 目标网站 加密分析 加密定位 结尾 本文仅供学习使用 切勿非法使用 如有侵权请联系作者及时删除 前言 无意中看到一个网站采用国密SM2算法进行登陆参数进行加密 之前接触的加密基本都是国外的算法 例如RSA DES MD5等等 国
  • 13位时间戳单位为毫秒,10位字符串单位为秒。时间戳转换日期数字格式100%全乎

    时间戳转换为年月日时分秒数字格式 注意时间戳有2种 13位时间戳 单位为毫秒 10位字符串 单位为秒 接口返回1616160878418 微秒 期望格式2021 03 19 21 34 35 标签 java new Date 变成GMT G
  • tar打包备份+ubuntu系统的修复

    如果ubuntu系统出问题 通过备份文件可以简单快速地修复ubuntu系统 tar打包十分必要 一 tar打包备份 1 进入管理员账户 sudo su 2 打包 tar cvPzf 20191203ubuntu1804 tgz exclud
  • 关于static 的各种数据类型 及在面向对象编程中的应用

    一 按存储区域分 全局变量 静态全局变量和静态局部变量都存放在内存的静态存储区域 局部变量存放在内存的栈区 1定义全局静态变量的好处 lt 1 gt 不会被其他文件所访问 修改 lt 2 gt 其他文件中可以使用相同名字的变量 不会发生冲突
  • 2023杭电暑假多校4 题解

    3 Simple Set Problem 题意 k 个多重集合 每个集合选出一个数形成新集合A 求 m a x A m
  • macos多合一系统安装u盘制作器_U 盘多系统安装盘制作神器YUMI

    通常我们一个 U 盘只能制作成一个系统安装盘 比如制作好一个 Windows 10 安装盘 日后想要用到 Linux WinPE 等安装盘时 只能重新制作一遍 非常浪费时间 而且现在 U 盘容量都很大 如果只放一个系统 同样就会白白浪费 U
  • 软考-操作系统

    考点梳理 进程管理 考点1 进程的状态 考法分析 本考点主要考查形式主要是根据图示判断相关状态位置或状态变迁条件 要点分析 操作系统三态模型如下图所示 操作系统五态模型 备考点拨 掌握操作系统三态模型 五态模型的状态位置及其状态变迁条件 考
  • arcgis 10.8 for win10安装教程

    本文主要记录arcgis安装步骤 遇到的问题等 文章目录 一 前提 二 下载与安装 1 下载 2 安装 参考资料 一 前提 下载前需要确定 1 ArcGIS对系统的要求 安装之前系统需安装 net framework 4 5 以上版本 我的
  • 【翻译】 WireGuard 何去何从?

    请考虑订阅 LWN订阅是 LWN net 的生命线 如果您喜欢这些内容并希望看到更多 您的订阅将有助于确保 LWN 继续蓬勃发展 请访问此页面加入我们 让 LWN 继续在网络上传播 作者 Jonathan Corbet 2019年3月25日
  • Angular2 之 单元测试

    单元测试需要掌握的知识点 karma conf js的配置 具体了解到每一项的意义 这样才能真正的了解这个配置是如何配置的 甚至才可以做到自己的配置 组件的测试 单独的service测试 Angular的测试工具 Angular的测试工具类
  • 飞机大战(C语言版)

    大一下要交课程设计 于是就用C语言写了一个飞机大战小游戏 没有用到第三方库 飞机和子弹的移动使用的光标移动函数 所以没有卡顿 其中w s a d分别表示上下左右 包括大写 空格发射子弹 游戏结束后可选择是否储存游戏数据 该程序复制后可直接使
  • git push错误: failed to push some refs to

    原因 当你在git上对它进行了在线修改 但是没有对本地库进行同步 这个时候你再次commit 想把本地库提交到远程git库中 就会出现push失败问题 简单来说 就是远程与本地存在不一致的commit情形 解决方法 确保远程代码没问题的情况
  • 【Java SE】抽象类和接口

    点进来你就是我的人了博主主页 戳一戳 欢迎大佬指点 欢迎志同道合的朋友一起加油喔 目录 前言 一 抽象类 1 抽象类的概述 2 抽象类特点 3 抽象关键字abstract和哪些不可以共存 4 抽象类的细节 5 抽象类的作用 二 接口 1 什
  • 统计学习方法论概念

    1 统计学习包含监督学习 非监督学习 半监督学习和强化学习 2 监督学习 监督学习的任务是学习一个模型 使模型能够根据任意给定的输入 对模型的输出做出一个好的预测 监督学习分为学习和预测两个过程 由学习系统和预测系统组成 3 损失函数和风险
  • 【C++】迭代器 && vector中迭代器失效

    文章目录 1 什么是迭代器 2 迭代器与指针 3 迭代器的分类 3 1具体分类 3 2为什么要对迭代器分类 3 3迭代器的使用建议 4 vector迭代器失效 4 1迭代器失效及其危害 4 2哪些操作会导致迭代器失效 如何解决 1 什么是迭