当前位置: 首页 > news >正文

C++迭代器失效

        在STL中,有些操作会导致迭代器失效,即之前获取的迭代器无法再安全地使用。这是因为这些操作可能会改变容器的结构,例如插入、删除元素等。

        具体来说,以下情况下迭代器会失效:

1. 当插入或删除元素导致容器中的内存重新分配时,所有指向容器元素的迭代器都会失效。这是因为容器重新分配了内存空间,原来的迭代器指向的内存已经无效。
2. 当插入元素导致迭代器位置被移动时,被移动的迭代器和之后的所有迭代器都会失效。这是因为插入元素后,容器中的元素位置发生了改变。
3. 当删除元素导致迭代器位置被移动或失效时,被删除元素的迭代器和之后的所有迭代器都会失效。这是因为删除元素后,容器中的元素位置发生了改变或者被删除的元素迭代器已经不存在。
4. 当对容器进行排序操作时,迭代器的相对顺序可能发生变化,因此之前的迭代器可能会失效。

        为避免迭代器失效,可以采取以下策略:

1. 尽量避免在循环中进行插入和删除元素的操作。如果必须进行这些操作,可以使用插入和删除后返回新的迭代器,而不是继续使用之前的迭代器。
2. 在遍历容器时,尽量使用前向迭代器或双向迭代器,避免使用随机访问迭代器。因为前向迭代器和双向迭代器的失效范围更小,而随机访问迭代器的失效范围更大。
3. 在可能引起迭代器失效的操作之后,务必更新迭代器,保证它们仍然指向有效的位置。
4. 如果需要在迭代器失效的情况下继续操作容器,可以使用容器提供的索引值或其他标识来重新获取迭代器。

        总之,迭代器失效是在使用STL容器时需要注意的问题,了解容器操作可能引起迭代器失效的情况,能够帮助避免潜在的错误。在编写代码时,建议谨慎使用迭代器,并在操作容器后适时更新迭代器,以确保程序的正确性。

4.1 示例

4.1.1 插入操作导致的迭代器失效

<1> vector 容器 

std::vector<int> v{1, 2, 3, 4, 5};
auto it = v.begin();v.insert(it + 2, 9); // 在迭代器位置之前插入元素// 插入元素后,原来的迭代器`it`已经失效,需要重新获取迭代器
it = v.begin();for (; it != v.end(); ++it) {std::cout << *it << " ";
}

输出结果:1 2 9 3 4 5

        在vector容器中,插入元素后,原来的迭代器会失效,因为插入元素后,可能会导致容器重新分配内存,迭代器指向的位置被移动。

<2> list容器 

std::list<int> lst{1, 2, 3, 4, 5};
auto it = lst.begin();lst.insert(std::next(it, 2), 9); // 在迭代器位置之后插入元素// 插入元素后,原来的迭代器`it`仍然有效
for (; it != lst.end(); ++it) {std::cout << *it << " ";
}

输出结果:1 2 3 9 4 5

        在list容器中,插入元素不会导致迭代器失效,因为list使用链表结构存储元素,插入元素后,原来的迭代器仍然保持有效。

 <3> map容器

std::map<int, std::string> m{{1, "one"}, {2, "two"}, {3, "three"}};
auto it = m.begin();m.insert(std::make_pair(4, "four")); // 插入键值对// 插入元素后,原来的迭代器`it`仍然有效
for (; it != m.end(); ++it) {std::cout << it->first << ":" << it->second << " ";
}

输出结果:1:one 2:two 3:three 4:four

map容器中,插入元素不会导致迭代器失效。

4.1.2 删除操作导致的迭代器失效

下面是一个示例代码,演示了使用vector容器删除元素操作导致迭代器失效的情况:

#include <iostream>
#include <vector>int main() {std::vector<int> v{ 1, 2, 3, 4, 5, 6 };auto it = v.begin();while (it != v.end()) {if ((*it % 2) == 0) {std::cout << "erase " << *it << std::endl;v.erase(it); // 删除偶数元素}else {it++;}}return 0;
}

        这个程序会遍历vector容器v中的所有元素,如果某个元素是偶数,则删除它。然而,这个程序存在迭代器失效的问题,因为在删除元素后继续使用同一个迭代器进行遍历容器。事实上,运行这个程序会导致Segmentation fault错误,并且程序崩溃。

        这个程序的问题在于,在执行v.erase(it)操作后,迭代器it指向的位置已经变为了被删除元素的下一个位置,而不是原来的下一个位置。因此,在使用it进行下一次循环遍历时,会访问到已经被删除的元素,从而导致异常。

vector iterator not incrementable错误通常是因为在使用vector容器的迭代器时出现了问题。这个错误可能由以下几种情况引起:

  1. 在循环中对迭代器进行了无效的增量操作。比如,在循环中使用++运算符对迭代器进行递增,但在某些条件下,没有确保迭代器仍然有效。这可能是由于删除元素或修改容器结构导致的。

  2. 在使用迭代器之前,对vector容器进行了修改操作。如果在使用迭代器进行遍历之前,对vector容器执行了插入、删除或排序等改变容器大小的操作,那么迭代器可能会失效。

要解决这个错误,可以考虑以下几点:

(1)确保在对迭代器进行增量操作之前,先判断迭代器是否有效。可以使用条件语句(如if)或循环控制语句(如while)来判断迭代器是否指向有效的元素。

   要判断迭代器是否有效,可以通过比较迭代器与容器的begin()end()迭代器进行判断。如果迭代器位于容器范围内,则表示迭代器有效;否则,表示迭代器无效。

以下是几种常见的方法来判断迭代器的有效性:

<1> 使用相等运算符(==!=):通过将迭代器与容器的begin()end()迭代器进行比较来判断迭代器是否位于容器范围内。例如:

std::vector<int> v{1, 2, 3, 4, 5};
auto it = v.begin();if (it != v.end()) {// 迭代器有效
} else {// 迭代器无效
}
 

<2> 使用std::distance()函数:std::distance()函数可以返回两个迭代器之间的距离。通过计算迭代器与容器的begin()end()迭代器之间的距离,可以判断迭代器是否在容器范围内。例如:

std::vector<int> v{1, 2, 3, 4, 5};
auto it = v.begin();if (std::distance(it, v.end()) >= 0) {// 迭代器有效
} else {// 迭代器无效
}
 

<3> 使用异常处理:有些容器提供了在迭代器失效时抛出异常的机制。例如,std::list容器在删除迭代器指向的元素后,迭代器会失效,并抛出std::list::iterator类型的异常。可以捕获这个异常来判断迭代器是否有效。例如:

std::list<int> lst{1, 2, 3, 4, 5};
auto it = lst.begin();try {// 在此处进行可能导致迭代器失效的操作
} catch (const std::list<int>::iterator& e) {// 迭代器无效
}
在使用迭代器时,注意避免对已经失效的迭代器进行操作,以免引发未定义行为。

(2)如果需要对vector容器进行修改操作,建议在遍历容器之前完成所有修改。

(3)如果需要在遍历过程中删除元素,可以使用正确的方式进行删除。可以使用返回新的迭代器的vector::erase()函数,并将其返回值赋值给迭代器,或者使用vector::erase()的重载版本,传递要删除的元素的位置范围。

为了解决这个问题,可以修改程序,使用返回新的迭代器的vector::erase()函数,如下所示:

#include <iostream>
#include <vector>int main() {std::vector<int> v{ 1, 2, 3, 4, 5, 6 };auto it = v.begin();while (it != v.end()) {if ((*it % 2) == 0) {std::cout << "erase " << *it << std::endl;it = v.erase(it); // 删除偶数元素,并返回新的迭代器}else {it++;}}return 0;
}

 输出结果:

        这个程序与之前的程序类似,但是使用了返回新的迭代器的v.erase(it)函数,在删除元素后将其返回值赋值给迭代器it,以保证下一次循环遍历时,迭代器指向的位置仍然是有效的。运行这个程序,会得到正确的输出,没有异常发生。

持续更新!!! 

相关文章:

C++迭代器失效

在STL中&#xff0c;有些操作会导致迭代器失效&#xff0c;即之前获取的迭代器无法再安全地使用。这是因为这些操作可能会改变容器的结构&#xff0c;例如插入、删除元素等。 具体来说&#xff0c;以下情况下迭代器会失效&#xff1a; 1. 当插入或删除元素导致容器中的内存重新…...

LuatOS-SOC接口文档(air780E)--iotauth - IoT鉴权库, 用于生成各种云平台的参数

iotauth.aliyun(product_key, device_name,device_secret,method,cur_timestamp) 阿里云物联网平台三元组生成 参数 传入值类型 解释 string product_key string device_name string device_secret string method 加密方式,”hmacmd5” “hmacsha1” “hmacsha256”…...

2005.6-2018.6月中国企业OFDI微观数据

2005.6-2018.6月中国企业OFDI微观数据 1、时间&#xff1a;2005.6-2018.6 2、范围&#xff1a;公司 3、指标&#xff1a;Year、Month、Chinese Entity、 Quantity in Millions 、Share size、Transaction Party、Sector、Subsector、Country、Region、BRI 4、数据解释&…...

Spring和SpringBoot学习

Spring和SpringBoot学习 Spring中常用注解及其作用 Spring中常用注解及其作用 SpringBoot注解扫描范围 SpringBoot | ComponentScan()注解默认扫描包范围分析 spring boot的包扫描范围 springBoot的自动扫描包范围 SpringBoot中new对象不能自动注入对象 SpringBoot中new对…...

P6510 奶牛排队

题目 P6510 奶牛排队 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 思路 1.dp求最大。&#xff08;dp即前后关联&#xff09;arr[]用于存储输入的数据&#xff0c;brr[i]用于存储以第i头牛为右端点的队列最大值。 2.数组空间不够大&#xff0c;我们可以自己开辟对空间&…...

修改ConsoleApplication17_2项目实现oss上线

首先创建号oss&#xff0c;上传文件&#xff0c;复制临时链接 木马内写 可以看到能成功上线但是有个问题就是占用cpu大小为9%左右&#xff0c;这里我用的是腾讯云oss实现的&#xff0c;用阿里云oss实现也是9%左右 我再次进行url的aes加密 还是百分之9左右&#xff0c; 这里…...

Android学习之路(21) 进程间通信-AIDL与Servce基本使用

Service 与 Thread 和 进程 之间的关系 进程&#xff1a;应用程序在内存中分配的空间。&#xff08;正在运行中的程序&#xff09;线程&#xff1a;负责程序执行的单元&#xff0c;也称为执行路径。&#xff08;需要线程来执行代码&#xff09;。一个进程至少包含一条线程&…...

【MATLAB源码-第54期】基于白鲸优化算法(WOA)和遗传算法(GA)的栅格地图路径规划最短路径和适应度曲线对比。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 ​1.白鲸优化算法&#xff08;WOA&#xff09;&#xff1a; 白鲸优化算法是一种受白鲸捕食行为启发的优化算法。该算法模拟了白鲸群体捕食的策略和行为&#xff0c;用以寻找问题的最优解。其基本思想主要包括以下几点&#x…...

关于计算机找不到vcomp140.dll无法继续执行怎么修复

在计算机使用过程中&#xff0c;我们可能会遇到各种问题&#xff0c;其中之一就是vcomp140.dll文件丢失。vcomp140.dll是一个动态链接库文件&#xff0c;它通常用于支持软件运行和系统功能。当这个文件丢失时&#xff0c;可能会导致程序无法正常运行&#xff0c;甚至系统出现错…...

qt-C++笔记之信号与槽

qt-C笔记之信号与槽 code review! 本文抄自公众号&#xff1a;嵌入式小生 文章目录 qt-C笔记之信号与槽一.信号2.1.信号的发出2.2.信号的处理 二.槽函数2.1.带有默认参数的信号和槽函数2.2.使用QObject::connect()将信号连接到槽函数的三种方法2.2.1.第一种方法&#xff1a;使…...

linux安装visual studio code

下载 https://code.visualstudio.com/ 下载.deb文件 安装 假如文件被下载到了 /opt目录下 进入Opt目录&#xff0c;右键从当前目录打开终端。 输入下面的安装命令。 sudo apt-get install ./code_1.83.1-1696982868_amd64.deb 安装成功。 配置 打开 visual studio cod…...

VM虚拟机创建centos7 64位系统提示此主机不支持64位客户机操作系统,此系统无法运行

VM虚拟机创建centos7 64位系统提示此主机不支持64位客户机操作系统,此系统无法运行 背景解决方案 背景 本身系统是window10 64位专业版系统&#xff0c;理论上不应该不支持64位的。 解决方案 最近安装docker开启了虚拟化hyper-v&#xff0c;关闭即可。 打开cmd&#xff08;…...

跟着NatureMetabolism学作图:R语言ggplot2转录组差异表达火山图

论文 Independent phenotypic plasticity axes define distinct obesity sub-types https://www.nature.com/articles/s42255-022-00629-2#Sec15 s42255-022-00629-2.pdf 论文中没有公开代码&#xff0c;但是所有作图数据都公开了&#xff0c;我们可以试着用论文中提供的数据…...

Linux进程与线程的内核实现

进程描述符task_struct 进程描述符&#xff08;struct task_struct&#xff09;pid与tgid进程id编号分配规则内存管理mm_struct进程与文件,文件系统 进程,线程创建的本质 clone函数原型线程创建的实现进程创建的实现 总结 进程描述符task_struct 进程描述符&#xff08;st…...

Flink学习之旅:(四)Flink转换算子(Transformation)

1.基本转换算子 基本转换算子说明映射&#xff08;map&#xff09;将数据流中的数据进行转换&#xff0c;形成新的数据流过滤&#xff08;filter&#xff09;将数据流中的数据根据条件过滤扁平映射&#xff08;flatMap&#xff09;将数据流中的整体&#xff08;如&#xff1a;集…...

CesiumJS 中绘制大多边形

本文翻译自Cesium官方&#xff0c;有改动。 本文中提及到的“大多边形”就如下图所示。 在Cesium的早期版本和一些引擎中&#xff0c;我们绘制这种跨度比较大的多边形&#xff0c;经常会看到一些奇怪的冲突问题&#xff0c;如下图所示。 要渲染任何几何体&#xff0c;我们必…...

FreeRTOS移植以及任务

FreeRTOS移植 1.在sys.h中需要把SYSTEM_SUPPORT_OS 改为 1&#xff0c;支持我们使用 FreeRTOS //0,不支持 os //1,支持 os #define SYSTEM_SUPPORT_OS 1 //定义系统文件夹是否支持 OS2.出现报错 …\SYSTEM\usart\usart.c(6): error: #5: cannot open source input file “incl…...

笙默考试管理系统-MyExamTest----codemirror(41)

笙默考试管理系统-MyExamTest----codemirror&#xff08;40&#xff09; 目录 一、 笙默考试管理系统-MyExamTest 二、 笙默考试管理系统-MyExamTest 三、 笙默考试管理系统-MyExamTest 四、 笙默考试管理系统-MyExamTest 五、 笙默考试管理系统-MyExamTest 笙默考试…...

C#数据结构--数组和ArrayList

目录 本章目录&#xff1a; 2.1 数组基本概念 2.1.1 数组的声明和初始化 2.1.2 数组元素的设置和存取访问 2.1.4 多维数组 2.1.5 参数数组 2.2ArrayList 类 2.2.1ArrayList 类的成员 2.2.2 应用 ArrayList 类 数组和ArrayList之间的区别以及使用的场景 数组&#xf…...

Stable Diffusion WebUI扩展adetailer安装及功能介绍

ADetailer是Stable Diffusion WebUI的一个扩展,类似于检测细节器。 目录 安装地址 如何安装 1. Windows系统 (1)手动安装 (2)一体机...

Go语言的runtime.MemProfile中的集成监控环境生产

Go语言作为现代高性能编程语言的代表&#xff0c;其内置的runtime.MemProfile为开发者提供了强大的内存监控能力。在生产环境中&#xff0c;内存泄漏或异常使用往往是性能瓶颈的隐形杀手&#xff0c;而runtime.MemProfile通过集成监控环境&#xff0c;能够帮助开发者实时捕捉和…...

如何在 WooCommerce 后台按订单总金额精准筛选订单

本文详解如何在 WooCommerce 管理后台为「订单列表」添加基于固定价格&#xff08;如 $0、$18、$36&#xff09;的下拉筛选器&#xff0c;通过正确挂钩 restrict_manage_posts 和 request 钩子&#xff0c;并使用 _order_total 元字段进行精确匹配&#xff0c;实现高效、稳定的…...

车规级安全芯片HSM与SE:从标准到实战的供应链安全全景

1. 车规级安全芯片的核心标准解读 第一次接触车规级芯片时&#xff0c;我被各种英文缩写砸得头晕——AEC-Q100、ISO 26262、EAL...后来在某个凌晨三点调试ECU的项目里才真正明白&#xff0c;这些标准不是纸上谈兵&#xff0c;而是关乎车辆生死的安全底线。AEC-Q100就像汽车的&q…...

完全免费的神器,支持批量操作

今天给大家推荐一个非常不错的图片压缩软件&#xff0c;这个软件完全免费&#xff0c;没有任何的广告&#xff0c;可以完全放心使用。 Imagine图片压缩 支持图片批量压缩 这个软件安装之后就可以直接使用了&#xff0c;我们可以看到它的界面非常简单&#xff0c;而且支持图片…...

外盘期货 Tick 级行情 API 开发服务

外盘期货 Tick 级行情 API 开发&#xff0c;核心是接入低延迟、稳定的实时逐笔成交 / 盘口数据流&#xff0c;用于量化、做市、行情展示等场景。主流路径是&#xff1a;经纪商原生 API / 专业数据服务商 API → WebSocket/CTP 兼容长连接 → 回调解析 Tick → 缓存 / 入库 / 策…...

实战教程:用 Python 从 0 到 1 实现一个具备联网搜索能力的 Agent

实战教程:用 Python 从 0 到 1 实现一个具备联网搜索能力的 Agent 1. 核心概念 在当今人工智能技术飞速发展的时代,“Agent”(智能体)已经成为了一个炙手可热的概念。简单来说,Agent 是一个能够感知环境、做出决策并执行行动的自主实体。当我们赋予 Agent 联网搜索的能力…...

Fish-Speech 1.5新手必看:3个参数调出完美语音,告别重复卡顿

Fish-Speech 1.5新手必看&#xff1a;3个参数调出完美语音&#xff0c;告别重复卡顿 1. 为什么你的语音合成总是不自然&#xff1f; 刚接触语音合成的朋友经常会遇到这样的困扰&#xff1a;生成的语音要么机械感十足&#xff0c;要么频繁重复字词&#xff0c;甚至出现莫名其妙…...

G-Helper终极指南:5分钟掌握华硕笔记本性能优化技巧

G-Helper终极指南&#xff1a;5分钟掌握华硕笔记本性能优化技巧 【免费下载链接】g-helper Lightweight, open-source control tool for ASUS laptops and ROG Ally. Manage performance modes, fans, GPU, battery, and RGB lighting across Zephyrus, Flow, TUF, Strix, Scar…...

WarcraftHelper:3步解决魔兽争霸3在Win11的兼容性问题

WarcraftHelper&#xff1a;3步解决魔兽争霸3在Win11的兼容性问题 【免费下载链接】WarcraftHelper Warcraft III Helper , support 1.20e, 1.24e, 1.26a, 1.27a, 1.27b 项目地址: https://gitcode.com/gh_mirrors/wa/WarcraftHelper 还在为魔兽争霸3在Windows 10/11上频…...

图解CentOS7.x SNMP服务部署与安全配置实战

1. SNMP服务基础认知 第一次接触SNMP时&#xff0c;我完全被那些专业术语搞晕了。简单网络管理协议&#xff08;Simple Network Management Protocol&#xff09;其实就像给服务器装了个"体检仪"&#xff0c;它能实时采集CPU、内存、磁盘等健康指标。想象一下医院里的…...