返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >[C++] STL_vector 迭代器失效问题
  • 428
分享到

[C++] STL_vector 迭代器失效问题

c++java数据库 2023-09-07 15:09:11 428人浏览 独家记忆
摘要

文章目录 1、前言2、情况一:底层空间改变的操作3、情况二:指定位置元素的删除操作4、g++编译器对迭代器失效检测4.1 扩容4.2 erase删除任意位置(非尾删)4.3 erase尾删

在这里插入图片描述

文章目录

1、前言

**迭代器的主要作用就是让算法能够不用关心底层数据结构,其底层实际就是一个指针,或者是对指针进行了封装,比如:string的迭代器就是原生指针char,vector的迭代器就是原生态指针T因此迭代器失效,实际就是迭代器底层对应指针所指向的空间被销毁了,而使用一块已经被释放的空间,造成的后果是程序崩溃(即如果继续使用已经失效的迭代器,程序可能会崩溃)。
对迭代器失效我们了解了,那么现在我们就分析,在vector中哪些操作会导致迭代器失效。

2、情况一:底层空间改变的操作

存在底层空间改变的函数接口有:resize、reserve、insert、assign、push_back等。
产生的原因:
这几个接口都存在扩容的问题,扩容的时候存在异地扩容,当异地扩容后,原本的空间被释放,但是迭代器指的是被释放空间,这就会导致迭代器的失效问题,会引发程序崩溃的问题。
解决方法:
一旦存在扩容,扩容后对迭代器更新一次,重新给迭代器赋值即可。
举例:
我们看一下insert接口。
在这里插入图片描述

我们由图中可以看到,当我们需要在3之前插入数据30,但是空间已经满了,因此我们需要进行扩容,扩容是异地开空间,开好空间将旧空间的数据拷贝回来,并将旧空间释放掉,_start指向新的空间头部,但是it指的是旧空间的位置,这就是迭代器失效。我们记住it相对于_start的相对位置,在新空间开好后,更新it,让其指向新空间的相对位置。(方式:计算出it到_start的距离len,开好新空间后,更新it为新的_start+len)。
代码实现:

iterator insert(iterator pos, const T& x){    assert(pos >= _start);    assert(pos <= _finish);    if (_finish == _endOfStorage)    {        size_t len = pos - _start;//先记下_start到pos位置的距离,因为扩容后迭代器pos就会失效        reserve(capacity() == 0 ? 4 : 2 * capacity());        pos = _start + len;//新的空间需要更新迭代器pos    }    iterator end = _finish - 1;    //挪动数据    while (end >= pos)    {        *(end + 1) = *end;        --end;    }    *pos = x;    ++_finish;    return pos;}

3、情况二:指定位置元素的删除操作

对于erase接口也会导致迭代器失效问题。那它是怎么导致的呢,我们来分析一下。
产生原因:
在erase删除pos位置元素后,pos位置之后的元素会往前搬移,没有导致底层空间的改变,理论上讲迭代器不应该会失效,但是:如果pos刚好是最后一个元素,删完之后pos刚好是end的位置,而end位置是没有元素的,那么pos就失效了。因此删除vector中任意位置上元素时,vs就认为该位置迭代器失效了。
在这里插入图片描述

#include using namespace std;#include int main(){    int a[] = { 1, 2, 3, 4 };    vector<int> v(a, a + sizeof(a) / sizeof(int));    // 使用find查找3所在位置的iterator    vector<int>::iterator pos = find(v.begin(), v.end(), 3);    // 删除pos位置的数据,导致pos迭代器失效。    v.erase(pos);    cout << *pos << endl; // 此处会导致非法访问    return 0;}

解决方法:
本质是因为尾删导致的迭代器失效问题,因此我们在尾删完后,返回it的下一个位置,我们的模拟实现是数据覆盖(it+1覆盖it),因此返回的还是it,一删之后 --_finish,当 it指的位置就是_finish 的时候正好也就停止了,因此也就解决了迭代器失效的问题。
代码实现:

iterator erase(iterator pos){    assert(pos >= _start);    assert(pos < _finish);    iterator it = pos + 1;    //挪动数据    while (it < _endOfStorage)    {        *(it - 1) = *it;        ++it;    }    --_finish;    return pos;}

4、g++编译器对迭代器失效检测

linux下,g++编译器对迭代器失效的检测并不是非常严格,处理也没有vs2019下极端。
我们来看下面这几种情况下,代码在vs2019和g++下不同的表现。

4.1 扩容

int main(){    vector<int> v{1,2,3,4,5};    for(size_t i = 0; i < v.size(); ++i)    cout << v[i] << " ";    cout << endl;        auto it = v.begin();    cout << "扩容之前,vector的容量为: " << v.capacity() << endl;    v.reserve(100);    cout << "扩容之后,vector的容量为: " << v.capacity() << endl;        while(it != v.end())    {        cout << *it << " ";        ++it;    }    cout << endl;        return 0;}

g++下运行结果:
在这里插入图片描述

vs2019下运行结果:
在这里插入图片描述

vs2019下程序崩溃了。
结论:当扩容后迭代器就是失效的,g++下虽然能运行,但是结果出错了,vs下直接程序崩溃。

4.2 erase删除任意位置(非尾删)

#include #include using namespace std;int main(){    vector<int> v{1,2,3,4,5};    vector<int>::iterator it = find(v.begin(), v.end(), 3);        v.erase(it);    cout << *it << endl;        while(it != v.end())    {        cout << *it << " ";        ++it;    }    cout << endl;        return 0;}

g++下运行结果:
在这里插入图片描述

vs2019下运行结果:
在这里插入图片描述

结论:在非尾删的删除中,空间是没有变的,迭代器指的是还是那块空间,g++下迭代器没有失效,删除后后面的数据前移,it位置没失效,vs下只要是erase,就判断为迭代器失效了。

4.3 erase尾删

int main(){vector<int> v{1,2,3,4,5,6};auto it = v.begin();while (it != v.end()){if (*it % 2 == 0)v.erase(it);++it;}for (auto e : v)cout << e << " ";cout << endl;return 0;}

g++下运行结果:
在这里插入图片描述

vs2019下不用看,直接崩溃。
结论:当在尾删的时候,删除之后存在数据挪动,一挪动_finish与it是一个位置了,erase本就返回被删除位置的下一个位置,此时迭代器失效,再++it程序直接崩溃。

5、总结

本篇主要讲了扩容、插入、删除造成的迭代器失效,g++对迭代器失效检测的不严格,而vs对迭代器失效检测很严格,直接崩溃。
1、扩容一般都要更新迭代器,我们不知道哪一次的扩容是异地扩。
2、插入任意位置时,一旦存在扩容就要更新迭代器,本质就是扩容要更新迭代器。
3、删除任意位置时,g++下非尾删不考虑迭代器失效问题,尾删一定要注意迭代器失效问题;vs2019中删除就认定为迭代器失效,直接崩溃。

来源地址:https://blog.csdn.net/Ljy_cx_21_4_3/article/details/132517537

--结束END--

本文标题: [C++] STL_vector 迭代器失效问题

本文链接: https://lsjlt.com/news/398477.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • [C++] STL_vector 迭代器失效问题
    文章目录 1、前言2、情况一:底层空间改变的操作3、情况二:指定位置元素的删除操作4、g++编译器对迭代器失效检测4.1 扩容4.2 erase删除任意位置(非尾删)4.3 erase尾删 ...
    99+
    2023-09-07
    c++ java 数据库
  • C/C++迭代器的失效问题详解
    目录前言下面是我今天做的一些代码测试:我们接着往下看下一个出问题的测试代码:迭代器失效总结前言 我今天在使用迭代器时发现了一个问题,这个问题就是我在使用的迭代器时发现莫名其妙的有越界...
    99+
    2024-04-02
  • C++迭代器失效问题及解决
    目录什么是迭代器迭代器失效顺序容器迭代器失效添加操作删除操作关联容器迭代器失效swap()操作迭代器为什么不失效注意事项总结什么是迭代器 迭代器不是指针,是类模板,表现的像指针。他只...
    99+
    2023-02-10
    C++迭代器失效 C++迭代器 迭代器失效
  • C++中vector迭代器失效问题详解
    目录问题: (1)删除vector中所有的偶数(2)vector容器插入元素问题迭代器失效原因解决:总结问题:  (1)删除vector中所有的偶数 #i...
    99+
    2024-04-02
  • C++Vector迭代器失效问题的解决方法
    目录一、迭代器失效二、可能引起的迭代器失效的操作2.1、野指针引起迭代器失效2.2、迭代器指向的位置意义改变2.3、总结一、迭代器失效 主要作用就是让算法能够不用关心底层数据结构,其...
    99+
    2022-11-13
    C++ Vector迭代器失效 C++ 迭代器失效
  • c++迭代器失效的情况有哪些
    在C++中,迭代器可以在以下情况下失效: 添加和删除元素:如果在迭代器指向的容器中添加或删除元素,迭代器通常会失效。这是因为添加...
    99+
    2023-10-27
    c++
  • Scrapy之迭代爬取网页中失效问题及解决
    目录引言问题的提出问题分析问题的解决总结引言 在Scrapy中,在很多种情况下,需要一层层地进行爬取网页数据,就是基于url爬取网页,然后在从网页中提取url,继续爬取,循环往复。 ...
    99+
    2022-12-19
    Scrapy迭代 迭代爬取网页 迭代爬取网页失效
  • map迭代器遍历失效怎么解决
    如果在使用 map 迭代器遍历时失效,可能是因为在迭代器遍历的过程中修改了 map 的结构,导致迭代器失效。 为了解决这个问题,可以...
    99+
    2024-03-11
    map
  • packagesToScan失效问题
    packagesToScan失效问题是指在进行扫描操作时,packagesToScan配置项无效,导致无法扫描到相应的包。解决这个问...
    99+
    2023-09-08
    packagesToScan
  • C++特性:迭代器
    1. 迭代器(Iterator)的介绍 背景:指针可以用来遍历存储空间连续的数据结构,但是对于存储空间费连续的,就需要寻找一个行为类似指针的类,来对非数组的数据结构进行遍历。 定义...
    99+
    2024-04-02
  • 关于Python迭代器的问题有哪些
    这篇文章主要讲解了“关于Python迭代器的问题有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“关于Python迭代器的问题有哪些”吧!第一个问题:什么是迭代器迭代器,英文  ...
    99+
    2023-06-16
  • C++迭代器iterator详解
    目录1.迭代器分类1) 正向迭代器2) 常量正向迭代器3) 反向迭代器4) 常量反向迭代器2.迭代器用法示例3.迭代器:++it 与 it++ 哪个好?(1)前置返回一个引用,后置返...
    99+
    2024-04-02
  • c++下迭代器总结
    目录1. 迭代器介绍2. 初始化3. 常用操作总结1. 迭代器介绍 本章并不研究不同类型的迭代器,只总结常见迭代器的使用和误区。 定义:迭代器(iterator)有时又称光标(cur...
    99+
    2024-04-02
  • 迭代器的应用以及说明的问题
    一般使用for循环的顺序:   先创建一个迭代器:列表,并且列表内已存在数据   接着使用 for循环遍历列表   但这样存在一个问题,假如列表内的数据量很大,这样还未使用for循环便已经被列表占用很大的资源 这时我们就可以将这个迭代器做...
    99+
    2023-01-30
    迭代
  • C#迭代器方法介绍
    目录1.迭代器方法2.手动实现迭代器方法1.迭代器方法 可以使用foreach循环语句进行的迭代的方法,称为可迭代方法,或者迭代器方法。 迭代器用法法介绍。   迭代器用于依次返回每...
    99+
    2024-04-02
  • Python 迭代器和生成器:面试中常见问题
    ...
    99+
    2024-04-02
  • C++错误使用迭代器超出引用范围问题如何解决
    这篇文章主要介绍“C++错误使用迭代器超出引用范围问题如何解决”,在日常操作中,相信很多人在C++错误使用迭代器超出引用范围问题如何解决问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”C++错误使用迭代器超出引...
    99+
    2023-07-05
  • 解决mybatisplusMetaObjectHandler失效的问题
    目录一、什么是metaObjectHandler二、失效场景及解决方案一、什么是metaObjectHandler MetaObjectHandler接口是mybatisPlus为我...
    99+
    2023-02-05
    mybatisplus MetaObjectHandler 失效 mybatisplus MetaObjectHandler
  • Python 迭代器与生成器:如何解决性能问题
    ...
    99+
    2024-04-02
  • C++错误使用迭代器超出引用范围问题及解决方案
    目录前言相关错误错误截图错误原因解决方案Visual Studio 更新日志前言 今天在调用一个URI解析库的时候,在clang的编译器上代码能正常编译,在visual studio...
    99+
    2023-03-24
    C++迭代器超出引用范围 C++错误使用迭代器 c++迭代器
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作