c++迭代器失效

2023-11-09

 下面材料整理自Internet&著作。
  STL中的容器按存储方式分为两类,一类是按以数组形式存储的容器(如:vector 、deque);另一类是以不连续的节点形式存储的容器(如:list、set、map)。在使用erase方法来删除元素时,需要注意一些问题。

1.list,set,map容器

     在使用 list、set 或 map遍历删除某些元素时可以这样使用:

1.1 正确写法1


  
  
  1. 1 std ::list< int> List;
  2. 2 std ::list< int> ::iterator itList;
  3. 3 for( itList = List .begin(); itList != List .end(); )
  4. 4 {
  5. 5 if( WillDelete( *itList) )
  6. 6 {
  7. 7 itList = List.erase( itList);
  8. 8 }
  9. 9 else
  10. 10 itList++;
  11. 11 }

1.2 正确写法2


  
  
  1. 1 std ::list< int> List;
  2. 2 std ::list< int> ::iterator itList;
  3. 3 for( itList = List .begin(); itList != List .end(); )
  4. 4 {
  5. 5 if( WillDelete( *itList) )
  6. 6 {
  7. 7 List.erase( itList++);
  8. 8 }
  9. 9 else
  10. 10 itList++;
  11. 11 }

1.3 错误写法1


  
  
  1. 1 std ::list< int> List;
  2. 2 std ::list< int> ::iterator itList;
  3. 3 for( itList = List .begin(); itList != List .end(); itList++)
  4. 4 {
  5. 5 if( WillDelete( *itList) )
  6. 6 {
  7. 7 List.erase( itList);
  8. 8 }
  9. 9 }

1.4 错误写法2


  
  
  1. 1 std ::list< int> List;
  2. 2 std ::list< int> ::iterator itList;
  3. 3 for( itList = List .begin(); itList != List .end(); )
  4. 4 {
  5. 5 if( WillDelete( *itList) )
  6. 6 {
  7. 7 itList = List.erase( ++itList);
  8. 8 }
  9. 9 else
  10. 10 itList++;
  11. 11 }

1.5 分析

正确使用方法1:通过erase方法的返回值来获取下一个元素的位置
正确使用方法2:在调用erase方法之前先使用 “++”来获取下一个元素的位置
错误使用方法1:在调用erase方法之后使用“++”来获取下一个元素的位置,由于在调用erase方法以后,该元素的位置已经被删除,如果在根据这个旧的位置来获取下一个位置,则会出现异常。
错误使用方法2:同上。

2. vector,deque容器

在使用 vector、deque遍历删除元素时,也可以通过erase的返回值来获取下一个元素的位置:

2.1 正确写法


  
  
  1. 1 std ::vector< int> Vec;
  2. 2 std ::vector< int> ::iterator itVec;
  3. 3 for( itVec = Vec .begin(); itVec != Vec .end(); )
  4. 4 {
  5. 5 if( WillDelete( *itVec) )
  6. 6 {
  7. 7 itVec = Vec.erase( itVec);
  8. 8 }
  9. 9 else
  10. 10 itList++;
  11. 11 }

2.2 注意

注意:vector、deque 不能像上面的“正确使用方法2”的办法来遍历删除。原因请参考Effective STL条款9。摘录到下面:

1) 对于关联容器(如map, set, multimap,multiset),删除当前的iterator,仅仅会使当前的iterator失效,只要在erase时,递增当前iterator即可。这是因为map之类的容器,使用了红黑树来实现,插入、删除一个结点不会对其他结点造成影响。

 


  
  
  1. 1 for ( iter = cont .begin(); it != cont .end();)
  2. 2 {
  3. 3 (*iter)->doSomething();
  4. 4 if (shouldDelete(*iter))
  5. 5 cont.erase(iter++);
  6. 6 else
  7. 7 ++iter;
  8. 8 }

 

因为iter传给erase方法的是一个副本,iter++会指向下一个元素。
2)对于序列式容器(如vector,deque),删除当前的iterator会使后面所有元素的iterator都失效。这是因为vetor,deque使用了连续分配的内存,删除一个元素导致后面所有的元素会向前移动一个位置。还好erase方法可以返回下一个有效的iterator。


  
  
  1. 1 for ( iter = cont .begin(); iter != cont .end();)
  2. 2 {
  3. 3 (*it)->doSomething();
  4. 4 if (shouldDelete(*iter))
  5. 5 iter = cont.erase(iter);
  6. 6 else
  7. 7 ++iter;
  8. 8 }

3)对于list来说,它使用了不连续分配的内存,并且它的erase方法也会返回下一个有效的iterator,因此上面两种方法都可以使用。

3.迭代器失效的情况

3.1 vector

内部数据结构:数组。
随机访问每个元素,所需要的时间为常量。
在末尾增加或删除元素所需时间与元素数目无关,在中间或开头增加或删除元素所需时间随元素数目呈线性变化。
可动态增加或减少元素,内存管理自动完成,但程序员可以使用reserve()成员函数来管理内存。
vector的迭代器在内存重新分配时将失效(它所指向的元素在该操作的前后不再相同)。当把超过capacity()-size()个元素插入vector中时,内存会重新分配,所有的迭代器都将失效;否则,指向当前元素以后的任何元素的迭代器都将失效。当删除元素时,指向被删除元素以后的任何元素的迭代器都将失效。

3.2 deque

内部数据结构:数组。
随机访问每个元素,所需要的时间为常量。
在开头和末尾增加元素所需时间与元素数目无关,在中间增加或删除元素所需时间随元素数目呈线性变化。
可动态增加或减少元素,内存管理自动完成,不提供用于内存管理的成员函数。
增加任何元素都将使deque的迭代器失效。在deque的中间删除元素将使迭代器失效。在deque的头或尾删除元素时,只有指向该元素的迭代器失效。

3.3 list

内部数据结构:双向环状链表。
不能随机访问一个元素。
可双向遍历。
在开头、末尾和中间任何地方增加或删除元素所需时间都为常量。
可动态增加或减少元素,内存管理自动完成。
增加任何元素都不会使迭代器失效。删除元素时,除了指向当前被删除元素的迭代器外,其它迭代器都不会失效。

3.4 slist

内部数据结构:单向链表。
不可双向遍历,只能从前到后地遍历。
其它的特性同list相似。

3.5 stack

适配器,它可以将任意类型的序列容器转换为一个堆栈,一般使用deque作为支持的序列容器。
元素只能后进先出(LIFO)。
不能遍历整个stack。

3.6 queue

适配器,它可以将任意类型的序列容器转换为一个队列,一般使用deque作为支持的序列容器。
元素只能先进先出(FIFO)。
不能遍历整个queue。

3.7 priority_queue

适配器,它可以将任意类型的序列容器转换为一个优先级队列,一般使用vector作为底层存储方式。
只能访问第一个元素,不能遍历整个priority_queue。
第一个元素始终是优先级最高的一个元素。

3.8 set

键和值相等。
键唯一。
元素默认按升序排列。
如果迭代器所指向的元素被删除,则该迭代器失效。其它任何增加、删除元素的操作都不会使迭代器失效。

3.9 multiset

键可以不唯一。
其它特点与set相同。

3.10 hash_set

与set相比较,它里面的元素不一定是经过排序的,而是按照所用的hash函数分派的,它能提供更快的搜索速度(当然跟hash函数有关)。
其它特点与set相同。

3.11 hash_multiset

键可以不唯一。
其它特点与hash_set相同。

3.12 map

键唯一。
元素默认按键的升序排列。
如果迭代器所指向的元素被删除,则该迭代器失效。其它任何增加、删除元素的操作都不会使迭代器失效。

3.13 multimap

键可以不唯一。
其它特点与map相同。

3.14 hash_map

与map相比较,它里面的元素不一定是按键值排序的,而是按照所用的hash函数分派的,它能提供更快的搜索速度(当然也跟hash函数有关)。
其它特点与map相同。

3.15 hash_multimap

键可以不唯一。
其它特点与hash_map相同。

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

c++迭代器失效 的相关文章

  • 结构体如何存储在内存中?

    我有一个struct iof header在我的代码中 我确定它的宽度是 24 字节 我执行 sizeof iof header 它返回 32 字节宽 问题1为什么是 32 字节宽而不是 24 字节宽 问题2包括其成员在内 结构体如何存储在
  • fopen_s 怎么会比 fopen 更安全呢?

    我正在处理遗留代码Windows平台 当我编译代码时VS2013 它给出以下警告 错误 C4996 fopen 该函数或变量可能不安全 考虑使用fopen s反而 要禁用弃用 请使用 CRT SECURE NO WARNINGS 详情请参见
  • 为什么子函数不销毁GtkWindow?

    这是我的代码 void window first void enter window2 GtkWidget w gpointer data void quit GtkWidget w gpointer data void quit int
  • 嵌入资源文件的路径

    我的资源文件中有一个图标 我想引用它 这是需要图标文件路径的代码 IWshRuntimeLibrary IWshShortcut MyShortcut MyShortcut IWshRuntimeLibrary IWshShortcut W
  • 如何在C中同时运行两个子进程?

    所以我开始学习并发编程 但由于某种原因我什至无法掌握基础知识 我有一个名为 fork c 的文件 其中包含一个 main 方法 在此方法中 我将 main 分叉两次 分别进入子进程 1 和 2 在孩子 1 中 我打印了字符 A 50 次 在
  • 组合框下拉位置

    我有一个最大化的表单 其中包含 500px 的组合框控件 停靠在右上角 Width 尝试打开组合框后 列表的一半超出了屏幕 如何强制列表显示在表单中 棘手的问题 我找不到解决这个问题的好办法 只是一个解决方法 添加一个新类并粘贴如下所示的代
  • 无法加载程序集问题

    我收到以下错误 无法加载程序集 错误详细信息 System BadImageFormatException 无法加载文件或程序集 文件 或其依赖项之一 该程序集是由比当前加载的运行时更新的运行时构建的 无法加载 该程序集是使用 Net Fr
  • 如何减少 MinGW g++ 编译器生成的可执行文件的大小?

    我有一个简单的 Hello world C 程序 在 Win XP 下由 MinGW g 编译器编译为 500kB 可执行文件 有人说这是由于iostream的库和静态链接libstdc dll Using s链接器选项有点帮助 减少了 5
  • 控制台应用程序中使用 Unicode 字符的 _tprintf

    我正在从 Unicode 构建的控制台应用程序 使用 C 和 Visual Studio 2008 执行这个简单的输出 此代码旨在在 Windows 上运行 tprintf L Some sample string n 一切正常 但是如果我
  • 如何自定义 Google 测试失败消息?

    我编写了一个如下所示的 Google 测试 它将一些计算值与 CSV 文件中预期存储的值进行比较 class SampleTest public testing Test public void setupFile const std st
  • 在c#中获取没有时间的日期

    我的表上有一列 缺勤日期时间 日期 当我想要获取包含日期的行时 它返回 0 行 这是我的 C 代码 DateTime ClassDate DateTime Parse lblDate Content ToString var Abs dbs
  • 如何将STL容器数据转储到gdb中?

    我无法在 gdb 中转储 STL 无序映射容器值 变量类型是 std unordered map var 我的 gdb 版本 7 7 1 GDB配置 configure host x86 64 linux gnu target x86 64
  • 处理“未找到细胞”。 Excel 中的错误

    我正在使用 Excel VSTO 应用程序并使用以下代码在工作表中查找错误单元格 Excel Range rngTemp Excel Range rngErrorRange Excel Worksheet Sheet1 Excel Work
  • 我在使用 ado.net 时收到错误 Argument 2 may not be pass with ref keywords

    int t 0 cmd Parameters AddWithValue Res ref t 我在第二行收到错误 参数 2 不能与 ref 关键字一起传递 您只能通过引用传递参数ref if the 范围 is a ref参数也是如此 Add
  • 如何从外语线程调用Python函数(C++)

    我正在开发一个程序 使用 DirectShow 来抓取音频数据 媒体文件 DirectShow 使用线程将音频数据传递给回调 我的程序中的函数 然后我让该回调函数调用另一个函数 Python 中的函数 我使用 Boost Python 来包
  • 您对“大规模 C++ 软件设计”的看法 [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 正在阅读亚马逊评论 https rads stackoverflow com amzn click com 0201633620 and ACC
  • 当需要不同数量和类型的参数时如何创建操作委托列表

    我们有一组大约两打的类 它们继承自具有抽象 Validate 方法的基类 当然 每个类都有不同的验证需求 但它们之间的不同组合需要规则 因此 正如您可以想象的那样 这导致了大量代码重复 例如 A 类需要规则 1 3 6 和 9B 类需要规则
  • C#:自定义转换为值类型

    是否可以将自定义类转换为值类型 这是一个例子 var x new Foo var y int x Does not compile 是否有可能实现上述情况 我需要超载一些东西吗Foo 您将必须重载强制转换运算符 public class F
  • 如何从 Access 数据库中读取“是/否”值作为布尔值?

    帮我找回YES NO来自 MS Access 的布尔格式数据类型 我尝试解析它 但它总是返回 false 更新 实际上不是问题抱歉 它确实接受 YES NO 作为布尔值 OleDbconnection dbConnect new OleDb
  • 如何在 C 中创建最低有效位设置为 1 的掩码

    这个功能如何运作 最低有效 n 位设置为 1 的掩码 Example n 6 gt 0x2F n 17 gt 0x1FFFF 我根本不明白这些 尤其是 n 6 gt 0x2F 另外 什么是面膜 通常的方法是采取1 并将其左移n位 这会给你类

随机推荐

  • Adobe系列软件安装不上怎么办,别着急看这里

    最近有许多用户反映安装Adobe系列软件安装不上 如PS 安装提示 发生了未知错误 错误代码 1 这是因为你的电脑之前安装过PS 卸载不干净导致 可以参考本教程清理PS的残留文件 注意 此教程会清理所有Adobe相关文件 如果你只想清理PS
  • [转帖]阿里的JDK预热warmup过程

    预热warmup过程 https blog csdn net wabiaozia article details 82056520 Jwarmup 原理是记录上一次运行时已经变成native code 的class function 以及加
  • 汇编: mul乘法指令(字乘法结果在dx:ax中,8位乘法:一个乘数默认放在al中)

    版权声明 本文为博主原创文章 遵循 CC 4 0 BY SA 版权协议 转载请附上原文出处链接和本声明 本文链接 https blog csdn net m0 37564426 article details 85563170
  • linux--主机规划和磁盘分区

    linux与硬件的搭配 桌面计算机 Desktop 的用户 应该会用到 X Window 系统 此时 显示适配器的优劣与内存的大小可就占有很重大的影响 如果是想要做成文件服务器 那么硬盘或者是其他的储存设备 应该就是您最想要增购的组件 认识
  • 一个用于灰度标定的matlab函数

    处理图像时 导致像素值跨越由负数到正数的较宽范围的计算是很常见的 我们在计算的时候一般都是用的double类型哈 尽管在中间计算过程中不会导致问题 但当我们想要利用8位 uint8 或16位 uint16 格式保存或观看一幅图像时 就会出现
  • leetcode 数组

    知识点 二分 模板 有等号 704 34 35 69 367 双指针 两边向中间 快慢 中间向两边 26 27 283 844 977 1 移除元素 这里固定慢指针 遍历快指针 当然还是两头出发的写法更好懂 2 滑动窗口 209 904 7
  • CSS核心知识点

    目录 1 什么是CSS 1 1 快速入门 1 2 CSS 导入三种方式 2 选择器 2 1 基本选择器 2 2 层次选择器 2 3 结构伪类选择器 2 4 属性选择器 常用 3 美化网页元素 3 1 为什么要美化网页 3 2 字体样式 3
  • VMware16安装CentOS7.6虚拟机

    Centos7 6系统镜像下载 直接网页下载非常慢 建议下载torrent种子后用迅雷等下载工具下载 Centos7 6系统镜像 镜像实测可用 现在好多Centos7 6的镜像都挂掉了 上面的依然坚挺 创建虚拟机 gt 典型 稍后安装 选择
  • python使用matplotlib绘制折线图

    python使用matplotlib绘制折线图 Python绘图需要下载安装matplotlib模块 它是一个数学绘图库 我们将使用它来制作简单的图表 一 绘制单条折线图 import matplotlib pyplot as plt pl
  • 如何看论文(一)

    论文初步 开个头 即将进入研究生的大门 开始研究生的学习生活 将要面对成堆的论文 组会 以及等等 才发现最基础的看论文 也只是在大四毕设的时候粗略地尝试过几篇 离真正的看论文还差得很远 并且 在研究生阶段 按我的理解 看懂一篇文章没什么 讲
  • Ubuntu忘记密码(五个小步骤)

    Ubuntu忘记密码 五个小步骤 可能用到的操作 按键 鼠标操作 作用 进入虚拟机屏幕 点击 鼠标焦点在虚拟机中 接下来的操作都在虚拟机中响应 退出虚拟机屏幕 ctrl alt 将鼠标焦点从虚拟机中移除 回到主屏幕 步骤一 重启虚拟机 注意
  • 图形学实验四线段裁剪算法

    实验四 线段裁剪算法 实验类型 设计型 实验学时 2实验要求 必修 一 实验目的 了解二维图形裁剪的原理 点的裁剪 直线的裁剪 多边形的裁剪 利用VC OpenGL实现直线的裁剪算法 二 实验内容 1 理解直线裁剪的原理 编码裁剪算法 梁友
  • 采用python编写微信自动回复程序(基于图灵机器人)

    采用python编写微信自动回复程序 基于图灵机器人 写在开头 注册CSDN这么久 第一次发博客 难免有写得不明白的地方 请读者们谅解 一 要实现微信自动回复 需要如下准备 1 注册一个图灵机器人 现在是要收费的 不过一个月的费用也不是很贵
  • git中关于用户信息的命令

    一 前言 工作中需要查看git的一些用户信息 现将其记录如下 二 相关命令 查看当前项目的用户信息 该信息保存在项目下面隐藏文件夹 git config文件中 查看用户名称 git config user name 查看用户邮箱 git c
  • 通过Valgrind的Massif工具进行C++内存使用分析

    关于Valgrind的简介可以参考 https blog csdn net fengbingchun article details 50196189 Valgrind在Ubuntu上的安装可以参考 https blog csdn net
  • 【ARM】使用Ubuntu-base构建根文件系统

    使用Buildroot构建根文件系统 介绍 资源下载 配置根文件系统 设置软件源 安装必要软件 添加新用户 设置主机名称和本机IP 设置终端串口 网络DHCP FTP服务器搭建 串口无法登录 开机启动信息显示 Failed to inser
  • 硕士毕业生找工作经验体会(怎样才能说服你面前的HR)

    下个月就要离开交大了 这个我呆了将近7年的地方 最后想留下一点关于找工作方面的经验体会 从05年考研结束的时候开始找工作 之后知道研究生录取之后找实习 一直到07年正式找工作 期间我接触过很多行业 很多人 很多职位 从一开始 我就听无数人在
  • JavaEE 笔记01: 基于Tomcat, Servlet, JSP的简单作业管理系统

    基于Tomcat Servlet JSP的简单作业管理系统 目录 基于Tomcat Servlet JSP的简单作业管理系统 前言 2020年3月25日更新 2020年3月26日更新 2020年4月8日更新 2020年4月16日更新 202
  • 深聊性能测试,从入门到放弃之:Locust性能自动化(六)自定义生成负载图形形状

    自定义峰值形状 1 引言 2 定义 2 1 列举实例 2 2 如何继承 2 3 方法使用 3 代码实战 3 1 时间峰值 3 2 双波形 3 3 基于时间阶段 3 4 逐步加载 1 引言 今天分享的这部分内容 应该算是Locust的进阶篇
  • c++迭代器失效

    下面材料整理自Internet 著作 STL中的容器按存储方式分为两类 一类是按以数组形式存储的容器 如 vector deque 另一类是以不连续的节点形式存储的容器 如 list set map 在使用erase方法来删除元素时 需要注