【C++】迭代器失效问题解析


Blog’s 主页: 白乐天_ξ( ✿>◡❛)
🌈 个人Motto:他强任他强,清风拂山冈!
🔥 所属专栏:C++深入学习笔记
💫 欢迎来到我的学习笔记!

一、迭代器失效的概念

  1. 迭代器的作用与本质
  • 迭代器的主要作用是让算法无需关心底层数据结构,其底层实际为指针或对指针的封装。在vector中,迭代器本质上就是原生态指针T*(通过typedef定义为iterator,常量迭代器为const_iterator)。
namespace Harper 
{template<class T>class vector {public:// 迭代器的你故意typedef T* iterator;typedef const T* const_iterator;// 其他成员函数和变量的定义//...};
}
  1. 迭代器失效的本质
  • 迭代器失效即迭代器底层对应指针所指向的空间被销毁,继续使用这种已释放空间的迭代器会导致程序崩溃,具体表现为:
    • 迭代器本质是指针,所以迭代器失效就是指针失效。
    • 指针失效意味着指针指向的空间非法,如指向已被释放的空间或者越界访问。

二、导致迭代器失效的操作

  1. 扩容相关操作
  • resizereserveinsertassignpush_back等可能引起扩容的操作,都可能导致迭代器失效(由野指针引起)。下面是push_back为例的 :
void push_back(const T& value) 
{if (_finish == _end_of_storage) {size_t newcapacity = capacity() == 0? 4 : capacity() * 2;reserve(newcapacity);}*_finish = value;++_finish;
}
  • 在这个过程中,如果有其他迭代器指向原来的vector空间,那么在扩容后这些迭代器就可能失效。
  1. 指定位置的插入与删除操作
  • inserterase这类指定位置的操作,可能使迭代器指向的位置意义发生改变,从而导致迭代器失效。

三、避免迭代器失效的方法

3.1 insert函数的迭代器失效问题及解决

3.1.1 扩容导致野指针的情况

  • 问题描述:给出insert的初始版本代码,在测试中发现,例如先push_back尾插一定数量元素后调用insert可能出现随机值问题(如尾插4个元素后调用insert出现随机值,尾插5个调用insert无此问题)。这是因为pos未更新,扩容时_start_finish更新,而pos仍指向旧空间,旧空间释放后pos成为野指针,后续*pos = x操作非法访问野指针。

  • 解决方法:计算扩容前pos_start的相对距离n,扩容后让pos = _start + n,使pos始终指向正确位置。修改后的insert函数如下:

void insert(iterator pos, const T& x) 
{//检测参数合法性assert(pos >= _start && pos <= _finish);/*扩容以后pos就失效了,需要更新一下*/if (_finish == _end_of_stoage) {size_t n = pos - _start;size_t newcapcacity = capacity() == 0? 4 : capacity() * 2;reserve(newcapcacity);pos = _start + n;}//挪动数据iterator end = _finish - 1;while (end >= pos) {*(end + 1) = *(end);end--;}//把值插进去*pos = x;_finish++;
}

3.1.2 迭代器指向位置意义改变的情况

  • 问题描述:以在所有偶数前插入2为例,在测试代码中发现会发生断言错误。当insert插入可能扩容时,原空间数据拷贝到新空间,旧空间变为野指针,而外部迭代器it一直指向旧空间,遍历it时会非法访问野指针导致失效;即使不扩容,it指向位置意义改变,会导致程序重复插入元素。

  • 解决方法:给insert函数加上返回值(返回指向新插入元素的位置),调用时让迭代器接收insert的返回值。修改后的insert函数如下:

iterator insert(iterator pos, const T& x) 
{//检测参数合法性assert(pos >= _start && pos <= _finish);//检测是否需要扩容/*扩容以后pos就失效了,需要更新一下*/if (_finish == _end_of_stoage) {size_t n = pos - _start;size_t newcapcacity = capacity() == 0? 4 : capacity() * 2;reserve(newcapcacity);pos = _start + n;}//挪动数据iterator end = _finish - 1;while (end >= pos) {*(end + 1) = *(end);end--;}//把值插进去*pos = x;_finish++;return pos;
}

测试函数:

// 测试函数
void testinsert() 
{my_vector::vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);v1.push_back(6);my_vector::vector<int>::iterator it = v1.begin();while (it!= v1.end()) {if (*it % 2 == 0) {it = v1.insert(it, 20);}++it;}for (auto num : v1) {std::cout << num << " ";}std::cout << std::endl;
}

3.2 erase函数的迭代器失效问题及解决

  1. 问题描述

    • 给出erase的初始版本代码,erase的失效多为迭代器指向的位置意义发生改变或不在有效访问数据范围内。测试中发现,如删除vector中的元素后再访问或修改已删除元素的下一个元素可能出现问题(如尾插 4 个数字后删除特定元素,后续访问修改该元素下一个元素可能出错;删除所有偶数的测试中也会出现类似问题)。
  2. 解决方法

    • erase函数加上返回值(返回指向新插入元素的位置),调用时让迭代器接收erase的返回值。修改后的erase函数如下:
iterator erase(iterator pos) 
{//检查合法性assert(pos >= _start && pos < _finish);//从pos + 1的位置开始往前覆盖,即可完成删除pos位置的值iterator it = pos + 1;while (it < _finish) {*(it - 1) = *it;it++;}_finish--;return pos;
}

四、迭代器失效总结

vector迭代器失效主要有两种情况:

  1. 扩容、缩容导致野指针式失效。
  2. 迭代器指向的位置意义改变。

注意,系统越界机制检查不一定能检测到迭代器失效问题,编译实现的检查机制相对更可靠。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/437972.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【PyTorch】生成对抗网络

生成对抗网络是什么 概念 Generative Adversarial Nets&#xff0c;简称GAN GAN&#xff1a;生成对抗网络 —— 一种可以生成特定分布数据的模型 《Generative Adversarial Nets》 Ian J Goodfellow-2014 GAN网络结构 Recent Progress on Generative Adversarial Networks …

Python | Leetcode Python题解之第450题删除二叉搜索树中的节点

题目&#xff1a; 题解&#xff1a; class Solution:def deleteNode(self, root: Optional[TreeNode], key: int) -> Optional[TreeNode]:cur, curParent root, Nonewhile cur and cur.val ! key:curParent curcur cur.left if cur.val > key else cur.rightif cur i…

解决Excel时出现“被保护单元格不支持此功能“的解决办法,详细喂饭级教程

今天有个朋友发过来一个excel文件&#xff0c;本来想修改表格的内容&#xff0c;但是提示&#xff0c;被保护单元格不支持此功能&#xff0c;对于这个问题&#xff0c;找到一个解决方法&#xff0c;现记录下来&#xff0c;分享给有需要的朋友。 表格文件名为aaa.xls,以WPS为例。…

什么是转义字符

1.什么是转义字符 转义字符是一组特殊的字符&#xff0c;转义字符顾名思义就是&#xff1a;转变原来的意思。 比如&#xff1a;我们有一组字符&#xff0c;其中的n能完整的打印出来&#xff0c;如下&#xff1a; #include <stdio.h> int main() { printf("asnfd&…

Typora解决图片复制到其他博客平台,解决图片显示转存失败(CSDN除外)

目录 一、Typora这个Markdown编辑器的确好用1.1 安装 二、 问题“图片转存失败”2.1 问题具体显示如下&#xff1a;2.2 问题分析&#xff1a;其实就是图片在typora里面是使用的本地路径&#xff0c;因此不显示&#xff0c; 三、解决方案3.1打开Typora&#xff0c;按下述图片显示…

【Verilog学习日常】—牛客网刷题—Verilog企业真题—VL74

异步复位同步释放 描述 题目描述&#xff1a; 请使用异步复位同步释放来将输入数据a存储到寄存器中&#xff0c;并画图说明异步复位同步释放的机制原理 信号示意图&#xff1a; clk为时钟 rst_n为低电平复位 d信号输入 dout信号输出 波形示意图&#xff1a; 输入描…

网络原理-数据链路层

在这一层中和程序员距离比较遥远&#xff0c;除非是做交换机开发&#xff0c;否则不需要了解数据链路层 由AI可知&#xff1a; 数据链路层&#xff08;Data Link Layer&#xff09;是OSI&#xff08;Open Systems Interconnection&#xff09;七层网络模型中的第二层&#xff0…

Elasticsearch 开放推理 API 增加了对 Google AI Studio 的支持

作者&#xff1a;来自 Elastic Jeff Vestal 我们很高兴地宣布 Elasticsearch 的开放推理 API 支持 Gemini 开发者 API。使用 Google AI Studio 时&#xff0c;开发者现在可以与 Elasticsearch 索引中的数据进行聊天、运行实验并使用 Google Cloud 的模型&#xff08;例如 Gemin…

用网络分析仪测试功分器驻波的5个步骤

在射频系统中&#xff0c;功分器的驻波比直接关系到信号的稳定性和传输效率。本文将带您深入了解驻波比的测试方法和影响其结果的因素。 一、功分器驻波比 驻波(Voltage Standing Wave Ratio)&#xff0c;简称SWR或VSWR&#xff0c;是指频率相同、传输方向相反的两种波&#xf…

TCN模型实现电力数据预测

关于深度实战社区 我们是一个深度学习领域的独立工作室。团队成员有&#xff1a;中科大硕士、纽约大学硕士、浙江大学硕士、华东理工博士等&#xff0c;曾在腾讯、百度、德勤等担任算法工程师/产品经理。全网20多万粉丝&#xff0c;拥有2篇国家级人工智能发明专利。 社区特色&a…

macOS 开发环境配置与应用开发

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

mfc140u.dll缺失?快速解决方法全解析,解决mfc140u.dll错误

当你的电脑出现找不到mfc140u.dll的问题&#xff0c;不少用户在使用电脑时陷入了困扰。这个错误提示就像一道屏障&#xff0c;阻挡了用户正常使用某些软件。无论是办公软件、游戏还是专业的设计工具&#xff0c;一旦出现这个问题&#xff0c;都会导致软件无法正常运行。如果您也…

【AIGC】内容创作——AI文字、图像、音频和视频的创作流程

我的主页&#xff1a;2的n次方_ 近年来&#xff0c;生成式人工智能&#xff08;AIGC&#xff0c;Artificial Intelligence Generated Content&#xff09;技术迅速发展&#xff0c;彻底改变了内容创作的各个领域。无论是文字、图像、音频&#xff0c;还是视频&#xff0c;A…

【分布式微服务云原生】windows+docker+mysql5.7.44一主一从主从复制

目录 1. 主库设置2. 从库设置3. 验证主从复制内容汇总表格 摘要&#xff1a; 在Windows系统上通过Docker部署MySQL主从复制&#xff0c;以下是详细的步骤和命令&#xff0c;帮助你设置一主一从的MySQL复制环境。 1. 主库设置 步骤1&#xff1a;运行MySQL主库容器 docker run …

如何在 DAX 中计算多个周期的移动平均线

在 DAX 中计算移动聚合很容易。但是&#xff0c;计算一段时间内的移动平均值时会有一些陷阱。由于其中一些陷阱是定义问题&#xff0c;因此我们必须小心&#xff0c;不要选择错误的方法。让我们看看细节。欢迎来到雲闪世界。 添加图片注释&#xff0c;不超过 140 字&#xff08…

一种路径敏感的数据依赖分析算法

Falcon 1.方法1.1.Basic Rule1.2.改进算法1.3.跨函数分析 2.Evaluation2.1.设置2.2.value-flow分析2.3.Thin Slicing2.4.Bug Detection 参考文献 这篇工作发表于PLDI 24&#xff0c;提出了一种context- 以semi-path-sensitive的数据依赖分析算法&#xff0c;解决path-sensitive…

css中背景色、背景图的使用

1、同时使用背景色、背景图片 参考链接&#xff1a;链接 以下样式&#xff0c;背景色在图片下方(缺点&#xff1a;图片不透明时&#xff0c;背景色会被完全遮挡。) .header {height: 100%;width: 100%;background-color: #000;background-image: url(/static/images/back.pn…

thinkphp6开发的通用网站系统源码

thinkphp6开发的通用网站系统源码。 基于ThinkPHP6框架开发的通用后台权限管理系统&#xff0c;底层采用国内最流行的ThinkPHP6框架&#xff0c; 支持内容管理、文章管理、用户管理、权限管理、角色管理等功能。 代码下载百度网盘

jenkins部署Maven和NodeJS项目

在 Java 项目开发中&#xff0c;项目的编译、测试、打包等是比较繁琐的&#xff0c;属于重复劳动的工作&#xff0c;浪费人力和时间成本。以往开发项目时&#xff0c;程序员往往需要花较多的精力在引用 jar 包搭建项目环境上&#xff0c;跨部门甚至跨人员之间的项目结构都有可能…

基于SSM的宿舍管理系统 (源码+定制+文档)

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…