C++迭代器失效解决办法详解

 更新时间:2024年12月31日 08:32:35   作者:Octopus2077  
这篇文章主要介绍了迭代器失效的概念,以及在vector、list和map等容器中插入和删除操作导致迭代器失效的情况,文中通过代码介绍的非常详细,需要的朋友可以参考下

迭代器失效

定义

​ 迭代器失效是指在使用迭代器遍历容器(如vectorlistmap等)的过程中,由于容器内部结构发生了变化,导致原来的迭代器不再有效,不能正确地指向它原本所指向的元素或者不能按照预期的方式进行遍历。

以 vector 为例说明

插入操作导致的迭代器失效

​ 当在vector中插入元素时,如果插入操作导致了内存重新分配,那么所有指向该vector的迭代器都会失效。这是因为vector的存储是连续的内存空间,当插入元素使得当前容量不够时,vector会重新分配一块更大的内存空间,将原来的元素复制或移动到新的空间中,原来的迭代器所指向的内存地址就不再有效。

例:

#include <iostream>
#include <vector>
int main() {
    std::vector<int> v = {1, 2, 3};
    auto it = v.begin();
    v.push_back(4);  // 插入元素可能导致内存重新分配
    // 此时it可能已经失效,下面的操作可能会导致程序出错
    std::cout << *it << std::endl;
    return 0;
}

调整一下:

删除操作导致的迭代器失效

​ 在vector中删除元素后,被删除元素之后的迭代器都会失效。这是因为删除元素会导致后面的元素向前移动,迭代器原本指向的元素位置发生了改变。

如:

#include <iostream>
#include <vector>
int main() {
    std::vector<int> v = {1, 2, 3, 4};
    auto it = v.begin() + 1;  // 指向元素2
    v.erase(it);  // 删除元素2
    // 此时it已经失效,下面的操作可能会导致程序出错
    std::cout << *it << std::endl;
    return 0;
}

以 list 为例说明

插入操作

​ 对于list容器,插入操作不会导致迭代器失效。因为list是由节点组成的链表结构,插入新节点只是修改节点之间的链接关系,迭代器指向的节点本身并没有改变。

​ 例如:

#include <iostream>
#include <list>
int main() {
    std::list<int> l = {1, 2, 3};
    auto it = l.begin();
    l.insert(it, 0);  // 在头部插入元素0
    std::cout << *it << std::endl;  // it仍然有效,输出1
    return 0;
}

删除操作

​ 在list中删除一个元素后,只有指向被删除元素的迭代器会失效。其他迭代器不受影响,因为链表结构的特点使得删除操作只是调整节点之间的连接,不会像vector那样引起其他元素的移动。

​ 例如:

#include <iostream>
#include <list>
int main() {
    std::list<int> l = {1, 2, 3};
    auto it = l.begin();
    l.erase(it);  // 删除第一个元素1
    // it已经失效,不能再使用
    // 可以重新获取迭代器来遍历
    for (auto new_it = l.begin(); new_it!= l.end(); ++new_it) {
        std::cout << *new_it << std::endl;
    }
    return 0;
}

​ 又如:

在关联容器中的情况

对于关联容器(以map为例),插入操作不会导致迭代器失效,因为插入新元素只是在红黑树(map通常的底层实现)中添加一个节点,不会改变已有节点的地址。

删除操作会导致指向被删除元素的迭代器失效,但其他迭代器仍然有效,因为红黑树的结构调整不会影响其他节点的内存位置。
​ 例如:

#include <iostream>
#include <map>
int main() {
    std::map<int, int> m = {{1, 10}, {2, 20}};
    auto it = m.find(1);
    m.erase(it);  // 删除键为1的元素
    // it已经失效,不能再使用
    for (auto new_it = m.begin(); new_it!= m.end(); ++new_it) {
        std::cout << new_it->first << " " << new_it->second << std::endl;
    }
    return 0;
}

总结 

到此这篇关于C++迭代器失效解决的文章就介绍到这了,更多相关C++迭代器失效内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 详解C++中的双冒号 ::

    详解C++中的双冒号 ::

    这篇文章主要介绍了C++中的双冒号 ::,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2020-09-09
  • C++11线程、互斥量以及条件变量示例详解

    C++11线程、互斥量以及条件变量示例详解

    这篇文章主要介绍了C++11线程、互斥量以及条件变量,C++11增加了线程以及线程相关的类,很方便地支持了并发编程,使得编写多线程程序的可移植性得到了很大的提高,本文通过实例代码给大家详细讲解,需要的朋友可以参考下
    2023-03-03
  • Win10+VS2017新CUDA项目配置教程

    Win10+VS2017新CUDA项目配置教程

    这篇文章主要为大家详细介绍了Win10+VS2017新CUDA项目配置教程,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-09-09
  • C++控制台循环链表实现贪吃蛇

    C++控制台循环链表实现贪吃蛇

    这篇文章主要为大家详细介绍了C++控制台循环链表实现贪吃蛇,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-04-04
  • C++中String类常见题目分享

    C++中String类常见题目分享

    这篇文章主要为大家详细介绍了一些C++中String类的常见题目,文中的示例代码讲解详细,对我们掌握C++有一定的帮助,感兴趣的小伙伴可以了解一下
    2023-06-06
  • 如何通过UltraEdit解析BMP文件内部结构(BMP位图基础)

    如何通过UltraEdit解析BMP文件内部结构(BMP位图基础)

    我们先打开画图随便画一幅图并采用24位bmp图像格式保存,就得到了一张24位真彩色的位图,下面我们来详细分析bmp位图的各个组成部分,感兴趣的朋友跟随小编一起看看吧
    2021-08-08
  • Microsoft Visual C++ 程序的部署方法

    Microsoft Visual C++ 程序的部署方法

    由Microsoft Visual C++编译的程序动态链接到C运行时(/MD 或 /MDd),它必须运行DLL的一份拷贝(通常被叫作MSVCRT.DLL 或 MSVCRxx.DLL,其中xx代表Visual C++的版本)
    2013-04-04
  • C++深入讲解引用的特点及与指针的区别

    C++深入讲解引用的特点及与指针的区别

    引用是C++一个很重要的特性,顾名思义是某一个变量或对象的别名,对引用的操作与对其所绑定的变量或对象的操作完全等价,这篇文章主要给大家总结介绍了C++中引用的相关知识点,需要的朋友可以参考下
    2022-05-05
  • OpenCV实战之基于Hu矩实现轮廓匹配

    OpenCV实战之基于Hu矩实现轮廓匹配

    这篇文章主要介绍了利用C++ OpenCV实现基于Hu矩的轮廓匹配,文中的示例代码讲解详细,对我们学习OpenCV有一定的帮助,感兴趣的可以学习一下
    2022-01-01
  • C语言修炼之路悟彻数组真妙理 巧用下标破万敌上篇

    C语言修炼之路悟彻数组真妙理 巧用下标破万敌上篇

    在C语言和C++等语言中,数组元素全为指针变量的数组称为指针数组,指针数组中的元素都必须具有相同的存储类型、指向相同数据类型的指针变量。指针数组比较适合用来指向若干个字符串,使字符串处理更加方便、灵活
    2022-02-02

最新评论