C++(22)——容器的迭代器失效问题

2023-11-18

前言

我们在之前的学习中已经实现过list和vector的迭代器,那么在面试中经常会有面试官问到有关于迭代器的失效问题,那么为什么迭代器会失效呢?

原因

随着VS版本的迭代,g++版本的迭代,C++标准库容器以及迭代器的源码都有比较大的修改,但是迭代器失效的问题本质归纳起来就两点

  1. 不同容器的迭代器是不能进行比较的
  2. 容器的元素进行inserterase操作后,当前位置到末尾的迭代器 就全部失效了

注意当容器调用erase或insert方法后,当前位置到容器末尾元素的所有迭代器全部失效,或者扩容操作,申请新空间,迭代器都指向老内存,原来所有迭代器全部失效

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

我们使用STL的vector,模拟一下:

在这里插入图片描述
程序运行后,两次终端显示的程序返回码并不是0,而是-572378类似的数字,因此程序并没有正常运行。

那么,遇到这样的问题应该如何解决呢?

答:对插入,删除点的迭代器进行更新操作。
但其实erase方法可以返回当前位置的新的有效的iterator

于是修改代码如下:

#include<iostream>
#include<vector>
using namespace std;

int main()
{
	vector<int> vec;
	for (int i = 0;i < 20;++i)
	{
		vec.push_back(rand() % 100 + 1);
	}

	for (int it : vec)
	{
		cout << it << " ";
	}
	cout << endl;
	auto it = vec.begin();
	
	while(it != vec.end())
	{
		if(*it % 2 == 0)
		{
			it = vec.erase(it);
		}//删完就往前挪,不用++
		else
		{
			++it;
		}
	}

	for (;it != vec.end();++it)
	{
		if (*it % 2 == 0)
		{
			it = vec.insert(it, *it - 1);/
			++it;//注意这里要++两次,因为当前指向的是插入的元素,再++才会指向上一轮的那个元素,再++才会继续做判断
		}
	}
	for (int it : vec)
	{
		cout << it << " ";
	}
	cout << endl;

	return 0;
}

因此我们在使用迭代器时,如果对容器内部进行插入和删除操作时,我们一定要记得对迭代器进行更新。
学会了解决的方法,我们再来深究一下其底层实现的原理:以insert为例,以自定义vector为例,看一下它的实现方式:

iterator insert(iterator it,const T &val)
{
//不考虑扩容,不考虑it._ptr的合法性
	verify(it._ptr - 1, _last);
	T* p = it._ptr;
	while (p < _last - 1)
	{
		_allocator.destroy(p);
		_allocator.construct(p, *(p - 1));
		p++; 
	}
	_allocator.destroy(p);
	_last--;
	return iterator(this, it._ptr);
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++(22)——容器的迭代器失效问题 的相关文章

随机推荐

  • keil新工程编译问题

    1 新建工程 找不到first和last 需要在工程中添加相对应芯片的start XXX swenjian 2 移植操作系统 error L6200E Symbol SysTick Handler multiply defined 这是在操
  • cuda矩阵乘法(简单理解)

    提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 CUDA矩阵乘法 矩阵规模 一 一维并行 1 一维线程并行 thread 2 一维块线程并行 block 3 一维共享A一行程并行 shared 二 二维并行 1 共享存储二
  • 差分 【一维差分和二维差分】

    全文目录 一维差分 差分数组的构建 二维差分 差分矩阵的构建 一维差分 首先来了解一下差分的性质 差分是前缀和的逆运算 如果说前缀和是 S f n 那么差分就是 D f 1 n 也就是说 原数组是差分数组的前缀和 原数组 a i 差分数组
  • 自动化测试系列 —— UI自动化测试

    UI 测试是一种测试类型 也称为用户界面测试 通过该测试 我们检查应用程序的界面是否工作正常或是否存在任何妨碍用户行为且不符合书面规格的 BUG 了解用户将如何在用户和网站之间进行交互以执行 UI 测试至关重要 通过执行 UI 测试 测试人
  • 全球及中国可穿戴医疗设备市场潜力分析与投资动态调研报告2022-2028年

    全球及中国可穿戴医疗设备市场潜力分析与投资动态调研报告2022 2028年 修订日期 2022年2月 出版单位 鸿晟信合研究院 对接人员 周文文 内容分析有删减 了解详情可查看咨询鸿晟信合研究院专员 目录 第一章 可穿戴医疗设备行业相关概述
  • VS2019或者VS2017创建ASP.NET项目

    最近在学 NET Web应用程序开发 做个记录 默认大家的本机的IIS服务已经搭建好了 没有搭建好的自行百度 文章目录 首先是VS的相关配置 然后是项目的创建 发布网站 项目的发布 IIS配置 一 首先是VS的相关配置 首先打开VS2019
  • C# 获取本地主机IP地址

  • 数据库----------唯一约束、默认约束、零填充约束

    目录 1 唯一约束 Unique 1 概念 2 语法 3 添加唯一约束 4 删除唯一约束 2 默认约束 default 1 概念 2 语法 3 添加默认约束 4 删除默认约束 3 零填充约束 zerofill 了解即可 1 概念 2 操作
  • R语言基础

    专注系列化 高质量的R语言教程 推文索引 联系小编 付费合集 本篇总结一些关于工具包的问题 所指的 工具包 对应的英文原文是package s 本篇目录如下 1 工具包简介 2 安装工具包 2 1 CRAN 2 2 GitHub 2 3 离
  • SQL注入——DNSLOG注入

    SQL注入 DNSLOG注入 SQL注入 DNSLOG注入 SQL注入 DNSLOG注入 一 原理 一 原理 当我们遇到盲注漏洞的时候 注入过程没有回显 手工测试会花费大量的时间 如果用sqlmap跑数据的话 实际应用中很可能被目标服务器直
  • 如何在PyCharm中对自己的pySC2 Agent代码进行Debug

    PySC2环境在Win10系统上的部署与安装 请参考 https blog csdn net qq 38962621 article details 112798659 spm 1001 2014 3001 5501 PySC2自定义Age
  • docker单机编排工具docker-compose

    编排工具安装 本文为在linux系统中操作 首先是安装epel源 然后安装python的pip组件 利用pip安装docker compose 在安装完毕后 可以使用查看版本命令以及帮助命令查看所支持的子命令 wget O etc yum
  • CRM管理软件有哪些?这5款好用的CRM软件值得推荐!

    CRM软件最常在销售部门实施 作为销售人员自动化的中心枢纽 包括联系人 客户和机会管理 CRM软件通常与其他企业解决方案 例如ERP系统 营销自动化软件和客户服务软件 分开交付 但通常与其他业务应用程序集成以促进增强和协调的客户体验 目前市
  • 嵌入式常用通讯协议1(UART 、RS232、RS485、SPI、IIC)

    目录 1 常用通讯协议汇总 2 常见的电平信号及其电气特性 2 1 TTL电平 2 2 CMOS电平标准 2 3 RS232标准 2 4 RS485标准 3 UART 通用异步收发器 协议 3 1 UART定义 3 2 UART作用 3 3
  • LeetCode刷题C++

    5 最长回文字符串 给你一个字符串 s 找到 s 中最长的回文子串 划定步长 遍历判断 class Solution public string longestPalindrome string s if s size lt 2 retur
  • Vue 引入G2图表

    安装G2依赖 npm install antv g2 npm install antv data set vue ge 在Vue main js文件中引入G2 import G2 from antv g2 Vue use G2 模板中使用完
  • 深入理解链表:一种动态的线性数据结构

    文章目录 前言 1 概述 2 单向链表 3 单向链表 带哨兵 4 双向链表 带哨兵 5 环形链表 带哨兵 6 结语 前言 链表是我们在日常编程中经常使用的一种数据结构 它相比于数组具有更好的动态性能 但是 对链表的深入理解需要我们掌握其内在
  • Linux项目自动化构建工具-make/Makefile (●‘◡‘●)

    目录 1 为什么要使用make 2 makefile的基本语法与变量 1 为什么要使用make 假设我们的执行文件里面包含2个源文件 分别是main c test c 如果想要这个程序运行起来 那么就需要先编译 先对源文件进行编译 产生te
  • C语言之基本数据类型

    在学习C语言的时候 我们可能首先面对的就是C语言中基本的数据类型 下面来看一下C语言中一些基本的数据类型 基本数据类型 void 声明函数无返回值或无参数 声明无类型指针 显示丢弃运算结果 C89标准新增 char 字符型类型数据 属于整型
  • C++(22)——容器的迭代器失效问题

    前言 我们在之前的学习中已经实现过list和vector的迭代器 那么在面试中经常会有面试官问到有关于迭代器的失效问题 那么为什么迭代器会失效呢 原因 随着VS版本的迭代 g 版本的迭代 C 标准库容器以及迭代器的源码都有比较大的修改 但是