• 迭代器失效问题


    迭代器失效问题

    vector容器是一个顺序容器 类似于线性表 空间是连续的 而且其接口大多都是和迭代器关联起来的 但是它会存在一个迭代器失效的问题

    • 迭代器失效问题分为两类:

    1.经过某些操作后迭代器的意义发生改变
    2.迭代器指向的空间被释放后或者空间扩容后该迭代器就会失效(不可再使用)

    第一类

    例一:

    vector成员函数insert()涉及的迭代器失效问题

    void teststdvector()
    {
    	vector<int> v;
    	v.push_back(1);
    	v.push_back(3);
    	v.push_back(4);
    	v.push_back(9);
    	v.push_back(10);
    	v.push_back(12);
    	for (auto& e : v)
    	{
    		cout << e << endl;
    	}
    	vector<int>::iterator it = v.begin();
    	auto pos = find(v.begin(), v.end(), 3);
     	if(pos!=v.end())
        cout<<endl;
    	v.insert(pos, 88);
    	cout<<*pos<<endl;
    	
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    在vector容器中尾插数据,然后在用算法库里的find函数在v的迭代器区间内找指向3的迭代器,再调用insert函数 在3的位置插入一个88 之后在对该迭代器进行解引用访问(vector的迭代器是原生指针T*,所以可以解引用),这个时候就会出现迭代器失效了,因为插入数据后原先3位置的迭代器就会发生改变,3的位置插入了新的数据,那么原先3的迭代器就会指向新插入的数据,迭代器的意义发生了变化,这就是第一种迭代器失效问题!
    在这里插入图片描述在这里插入图片描述
    在这里插入图片描述

    对于迭代器失效的检查,vs下的pj版编译器 和 linux下的gcc编译器检查力度不同,vs下检查很严格,不允许访问失效的迭代器 linux 下基本不检查!

    下面是两个平台下上段代码的运行结果:

    vs 2019下打印完插入的数据后就运行崩溃了!vs 2013 的版本会直接断言报错。

    在这里插入图片描述

    linux下即使是失效的迭代器,仍然可以访问,程序正常运行通过,编译器不做检查。

    在这里插入图片描述

    同样vector的成员函数erase()也涉及迭代器失效问题:

    void teststdvector3()
    {
    	vector<int> v;
    	v.push_back(1);
    	v.push_back(3);
    	v.push_back(4);
    	v.push_back(9);
    	v.push_back(10);
    	v.push_back(12);
    	auto pos = find(v.begin(), v.end(), 3);
    	if (pos != v.end())
    	{
    		v.erase(pos);
    	}
    	cout << *pos << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在这里插入图片描述
    在这里插入图片描述

    erase的返回值是删除元素位置的下一个位置的迭代器 也就还是pos(我们传的迭代器),此时的pos的意义已经发生了改变,由原先元素的迭代器变成了其一个元素的迭代器,已经失效了,不能再通过该迭代器访问原先的元素!!!

    在这里插入图片描述

    例二

    用erase删除vector中所有偶数的方法

    下面先举例错误的方法:

    //错误的代码
    void testerase1()
    {
    	vector<int> v;
    	v.push_back(1);
    	v.push_back(2);
    	v.push_back(3);
    	v.push_back(4);
    	auto it = v.begin();
    	while (it != v.end())
    	{
            //正常的思路就是 如果迭代器一直往后走 迭代器指向元素是偶数 就删除 
    		if (*it % 2 == 0)
    		{
    			v.erase(it);
    		}
    		++it;
    	}
    	for (auto& e : v)
    	{
    		cout << e << endl;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    上述代码的运行图解:

    这种方法就会漏掉数据,相邻的偶数或者一奇一偶就会·漏掉元素

    正确的使用方法:

    要防止代码中的it迭代器盲目往后走 需要判断如果是删除了那么就让it等于当前位置的下一个位置 否则就往后走也就是如果删除就让it接收erase的返回值,因为其返回值就是删除元素的一个元素的迭代器!

    只需要改动一下代码即可

    void testerase4()
    {
    	vector<int> v;
    	v.push_back(1);
    	v.push_back(2);
    	v.push_back(3);
    	v.push_back(4);
    	auto it = v.begin();
    	while (it != v.end())
    	{
            //用if else控制 进行了删除操作就让it接收erase的返回值 
            //那么it就会变成已经删除元素的下一个元素的迭代器 符合逻辑
            //如果没有进行删除 说明是奇数 就让it往后++ 跳过奇数即可
    		if (*it % 2 == 0)
    		{
    			it = v.erase(it);
    		}
    		else
    		{
    			++it;
    		}
    	}
    	for (auto& e : v)
    	{
    		cout << e << endl;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    更改后的代码正常运行,如下:

    在这里插入图片描述

    第二类

    迭代器指向的空间已经被释放掉,再次使用该迭代器访问其原先指向的元素,就也会报错,因为该迭代器空间释放后就已经失效了,不可以再使用(就是野指针,vector的迭代器就是原生指针的封装)!!!

    在这里插入图片描述

    第二种迭代器失效就是要注意扩容后原先的迭代器是属于原来空间的,原空间被释放后其不能再直接使用,需要更新至新空间的位置上,才可以使用,否则就是失效的迭代器!!!

  • 相关阅读:
    蓝牙技术|Matter或能改变中国智能家居市场,蓝牙技术将得到进一步应用
    【MotionCap】conda 链接缺失的cuda库
    [ROC-RK3568-PC] [Firefly-Android] 10min带你了解PWM的使用
    Go :验证编译器是否检测到错误的switch语句(附完整源码)
    Cron表达式详解(配合例子)
    ASPICE标准快速掌握「2.2. 过程参考模型(Process Reference Model,PRM)」
    WPF入门教程系列二十四——DataGrid使用示例(1)
    ES7,ES8
    台湾大学李宏毅:图解卷积神经网络CNN
    java - 数据结构,时间复杂度和空间复杂度
  • 原文地址:https://blog.csdn.net/xbhinsterest11/article/details/126053521