C/C++迭代器的失效问题详解

 更新时间:2022年03月27日 16:07:26   作者:贫僧爱用飘柔  
这篇文章主要为大家详细介绍了C/C++迭代器的失效问题,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助

前言

我今天在使用迭代器时发现了一个问题,这个问题就是我在使用的迭代器时发现莫名其妙的有越界访问和获取的位置跟预期不符,经过一天的排查我发现不是所有情况下会出现这种问题,而是在容器删除和扩容时会发生越界或结果和预期不符的情况。

下面是我今天做的一些代码测试:

Text1

该函数的功能是把数组里面的所有偶数删除,遍历方式使用的是迭代器。

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
 {
 	vector<int> v{ 1, 2, 3, 4, 5, 6 };
	auto it = v.begin();
 	while (it != v.end()) 
 	{
 		if (!(*it % 2)) 
		{
			v.erase(it);
 		}
		++it; 
	}

	return 0;
 }

当我运行起来时发现有越界访问和结果不符合预期这两种情况。

我们接着往下看下一个出问题的测试代码:

Test2

该函数的功能是想改变指定位置为30

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main(void)
{
 	vector<int> v{ 1, 2, 3, 4, 5 };
  	auto pos =find(v.begin(), v.end(), 3);
   	v.reserve(100);
    *pos = 30;
 	return 0;
}

当该程序运行起来我发现出现了越界问题!

上面的问题我思考了许久都没想明白于是我开始去网找答案我找了一天看了数篇文章,终于解开困扰我多天的问题出现上述情况是因为迭代器失效了!!! 。

迭代器失效

迭代器失效并不是说迭代器就是完全失效而是会出现以下两种情况:

1.迭代器的意义变了

2.迭代器完全失效

情况1是指迭代器没完全失效只是它表示的意义和原来的意思不同了,如果不做处理的话会导致运行结果会预期有偏差。如出现Test1那样的结果本来是想把所有偶数删掉结果迭代器失效了导致部分没删掉且还有越界访问风险。

那么,这种问题有什么较好的解决方案呢?其实很简单我们每次进行操作的时候都要更新下迭代器坐标即可

Test1修改后

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
 {
 	vector<int> v{ 1, 2, 3, 4, 5, 6 };
	auto it = v.begin();
 	while (it != v.end()) 
 	{
 		if (!(*it % 2)) 
		{
            //由于删除导致迭代器失效,所以我们重新更新下迭代器即可
			it = v.erase(it);
 		}
		else
        {
            //当迭代器不是偶数是才移动,如果所有情况都迭代的话会导致迭代器失效
			++it; 
        }
	}

	return 0;
 }

情况2是指迭代器完全不能用了,如果还坚持使用会发生越界访问,因为此时的迭代器已经是一个野指针了迭代器的底层都是一个指针来维护的,当迭代器完全失效意味着该迭代器成为了野指针。

Test2 是想修改指定位置的值,但是在修改前发生了一次扩容而该扩容就是导致迭代器失效的罪魁祸首,因为发生扩容的话原来的空间会被丢弃重新开辟一段内存来使用,而迭代器的底层是一个指针,它还指向之前的内存而该内存因为被释放了所以我们没有了使用权此时的迭代器也就成为了野指针。

那么,这种问题如何解决呢?其实和上一个问题的解决方案一样,当迭代器可能会发生变化时我们需要对迭代器进行一个更新确保它是有效的迭代器。

Test2修改后

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main(void)
{
 	vector<int> v{ 1, 2, 3, 4, 5 };
  	auto pos =find(v.begin(), v.end(), 3);
  	//扩容导致迭代器成为野指针
   	v.reserve(100);
   	//这时如果还想更改指定位置的值,那么我们需要进行一个迭代器的更新
  	pos =find(v.begin(), v.end(), 3);
    *pos = 30;
 	return 0;
}

总结

当使用迭代器时只要内存或迭代器会发生变化,那么我们需要对迭代器进行一次更新确保它每次操作都一定是有效的,从而避免迭代器失效造成的越界访问和预期不符的情况。

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注脚本之家的更多内容!    

相关文章

  • C++11中的原子量和内存序详解

    C++11中的原子量和内存序详解

    这篇文章主要给大家介绍了关于C++11中原子量和内存序的相关资料,文中通过示例代码介绍地方非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-06-06
  • 利用C语言实现三子棋(井字棋)小游戏

    利用C语言实现三子棋(井字棋)小游戏

    这篇文章主要为大家详细介绍了利用C语言实现三子棋小游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-08-08
  • C++设计模式之备忘录模式

    C++设计模式之备忘录模式

    这篇文章主要介绍了C++设计模式之备忘录模式,本文讲解了什么是备忘录模式、备忘录模式的UML类图、备忘录模式的使用场合等内容,需要的朋友可以参考下
    2014-10-10
  • 浅谈c++构造函数问题,初始化和赋值问题

    浅谈c++构造函数问题,初始化和赋值问题

    下面小编就为大家带来一篇浅谈c++构造函数问题,初始化和赋值问题。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-12-12
  • C++中产生临时对象的情况及其解决方案

    C++中产生临时对象的情况及其解决方案

    这篇文章主要介绍了C++中产生临时对象的情况及其解决方案,以值传递的方式给函数传参,类型转换以及函数需要返回对象时,并给对应给出了详细的解决方案,通过图文结合的方式讲解的非常详细,需要的朋友可以参考下
    2024-05-05
  • C++实现PatchMatch图像修复算法

    C++实现PatchMatch图像修复算法

    这篇文章主要介绍了C++实现PatchMatch图像修复算法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-04-04
  • 详解C语言初阶基础

    详解C语言初阶基础

    这篇文章主要介绍了C语言中的初阶基础,介绍了其相关概念,具有一定参考价值。需要的朋友可以了解下,希望能够给你带来帮助
    2021-11-11
  • C++基于CMD命令行实现扫雷小游戏

    C++基于CMD命令行实现扫雷小游戏

    这篇文章主要为大家详细介绍了C++基于CMD命令行实现扫雷小游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-05-05
  • C语言入门篇--初识C语言及数据类型

    C语言入门篇--初识C语言及数据类型

    本篇文章是c语言基础篇,主要为大家介绍了C语言的基本类型,为大家介绍了什么是C语言,希望可以帮助大家快速入门c语言的世界,更好的理解c语言
    2021-08-08
  • OpenCV实现多图像拼接成一张大图

    OpenCV实现多图像拼接成一张大图

    这篇文章主要为大家详细介绍了OpenCV实现多图像拼接成一张大图,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-01-01

最新评论