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;
}

总结

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

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

(0)

相关推荐

  • c++迭代器失效的情况汇总

    一.序列式容器(数组式容器) 对于序列式容器(如vector,deque),序列式容器就是数组式容器,删除当前的iterator会使后面所有元素的iterator都失效.这是因为vetor,deque使用了连续分配的内存,删除一个元素导致后面所有的元素会向前移动一个位置.所以不能使用erase(iter++)的方式,还好erase方法可以返回下一个有效的iterator. for (iter = cont.begin(); iter != cont.end();) { (*it)->doSome

  • vector list map 遍历删除制定元素 防止迭代器失效的实例

    方法如下所示: // k_control.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include "stdio.h" #include <vector> #include <map> #include <string> #include <list> using namespace std; int _tmain(int argc, _TCHAR* argv[]) {

  • C++中vector迭代器失效问题详解

    目录 问题: (1)删除vector中所有的偶数 (2)vector容器插入元素问题 迭代器失效原因 解决: 总结 问题: (1)删除vector中所有的偶数 #include <iostream> #include <vector> using namespace std; int main() { vector<int> vec; for (int i = 0; i < 10; ++i) { vec.push_back(i); } //把vec容器中的所有偶数

  • 浅谈c++ stl迭代器失效的问题

    之前看<C++ Primier>的时候,也解到在顺序型窗口里insert/erase会涉及到迭代器失效的问题,并没有深究.今天写程序的时候遇到了这个问题. 1 莫名其妙的Erase 最初我的程序是酱紫的,别说话,我知道这样是有问题的,可这样是最直观的想法 int arr[]={0,1,2,3,4,5,6,7,8,9,10}; vector<int> a(arr,arr+sizeof(arr)/sizeof(*arr));for (auto it = a.begin(); it !=

  • 关于vector迭代器失效的几种情况总结

    在泛型编程还是STL的实际运用中,迭代器(iterator)无疑扮演者重要的角色.迭代器是一种类似于指针的对象(如可以内容提领,成员访问等),但他又不仅仅是一种普通的指针. 关于迭代器失效,我们可以看下面这个例子: #include<vector> #include<list> void PrintVector(const vector<int>& v) { vector<int>::const_iterator it = v.begin(); wh

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

    目录 前言 下面是我今天做的一些代码测试: 我们接着往下看下一个出问题的测试代码: 迭代器失效 总结 前言 我今天在使用迭代器时发现了一个问题,这个问题就是我在使用的迭代器时发现莫名其妙的有越界访问和获取的位置跟预期不符,经过一天的排查我发现不是所有情况下会出现这种问题,而是在容器删除和扩容时会发生越界或结果和预期不符的情况. 下面是我今天做的一些代码测试: Text1 该函数的功能是把数组里面的所有偶数删除,遍历方式使用的是迭代器. #include <iostream> #include

  • Python 中迭代器与生成器实例详解

    Python 中迭代器与生成器实例详解 本文通过针对不同应用场景及其解决方案的方式,总结了Python中迭代器与生成器的一些相关知识,具体如下: 1.手动遍历迭代器 应用场景:想遍历一个可迭代对象中的所有元素,但是不想用for循环 解决方案:使用next()函数,并捕获StopIteration异常 def manual_iter(): with open('/etc/passwd') as f: try: while True: line=next(f) if line is None: br

  • Python 迭代器与生成器实例详解

    Python 迭代器与生成器实例详解 一.如何实现可迭代对象和迭代器对象 1.由可迭代对象得到迭代器对象 例如l就是可迭代对象,iter(l)是迭代器对象 In [1]: l = [1,2,3,4] In [2]: l.__iter__ Out[2]: <method-wrapper '__iter__' of list object at 0x000000000426C7C8> In [3]: t = iter(l) In [4]: t.next() Out[4]: 1 In [5]: t.

  • java 中迭代器的使用方法详解

    java 中迭代器的使用方法详解 前言: 迭代器模式将一个集合给封装起来,主要是为用户提供了一种遍历其内部元素的方式.迭代器模式有两个优点:①提供给用户一个遍历的方式,而没有暴露其内部实现细节:②把元素之间游走的责任交给迭代器,而不是聚合对象,实现了用户与聚合对象之间的解耦. 迭代器模式主要是通过Iterator接口来管理一个聚合对象的,而用户使用的时候只需要拿到一个Iterator类型的对象即可完成对该聚合对象的遍历.这里的聚合对象一般是指ArrayList,LinkedList和底层实现为数

  • 分析Springboot中嵌套事务失效原因详解

    首先两个事务方法,其中一个调用另一个. @Transactional(rollbackFor = Exception.class) public void trance() { try { trance1();//调用下一个事务方法. } catch (Exception e) { e.printStackTrace(); } User user = new User(); ShardingIDConfig shardingIDConfig = new ShardingIDConfig(); u

  • Apache SkyWalking 修复TTL timer 失效bug详解

    目录 正文 SkyWalking OAP 角色 SkyWalking OAP 集群 Data TTL timer 配置 DataTTLKeeperTimer 定时任务 Bug 产生的原因 解决 Bug 正文 近期,Apache SkyWalking 修复了一个隐藏了近4年的Bug - TTL timer 可能失效问题,这个 bug 在 SkyWalking <=9.2.0 版本中存在. 关于这个 bug 的详细信息可以看邮件列表 lists.apache.org/thread/ztp4… 具体如

  • 8个Spring事务失效场景详解

    目录 前言 Spring事务原理 Spring事务失效场景 1. 抛出检查异常 2. 业务方法本身捕获了异常 3. 同一类中的方法调用 4. 方法使用 final 或 static关键字 5. 方法不是public 6. 错误使用传播机制 7. 没有被Spring管理 8. 多线程 总结 前言 作为Java开发工程师,相信大家对Spring种事务的使用并不陌生.但是你可能只是停留在基础的使用层面上,在遇到一些比较特殊的场景,事务可能没有生效,直接在生产上暴露了,这可能就会导致比较严重的生产事故.

  • python的迭代器与生成器实例详解

    本文以实例详解了python的迭代器与生成器,具体如下所示: 1. 迭代器概述:   迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退.   1.1 使用迭代器的优点   对于原生支持随机访问的数据结构(如tuple.list),迭代器和经典for循环的索引访问相比并无优势,反而丢失了索引值(可以使用内建函数enumerate()找回这个索引值).但对于无法随机访问的数据结构(比

  • Javascript的迭代器和迭代接口详解

    目录 1,什么是迭代器 2,自定义迭代接口 3,原生语言的迭代 总结 1,什么是迭代器 每一个可迭代对象都对应着一个可迭代接口[Symbol.iterator]: [Symbol.iterator]接口并不是迭代器,他是一个迭代器工厂函数,调用该迭代接口即可返回一个待执行状态的迭代器: 不同的原生全局对象都对应着不同的迭代器: const arr = new Array() const map = new Map() const set = new Set() console.log(arr[S

随机推荐