关于stl容器的迭代器失效问题

news2024/12/26 11:00:04

场景

  在项目中使用stl容器的时候,多线程环境下出错,调试很久发现问题是使用容器的时候由于容器扩容导致的线程不安全,还有扩容导致的迭代器失效问题,于是就想着把迭代器失效的问题总结一下。

场景重现1
  我在项目开发中使用vector时,由于扩容导致的迭代器失效。

#include <iostream>
#include <vector>
#include <list>
#include <deque>
#include <map>
#include <unordered_map>
#include <thread>
#include <algorithm>
using namespace std;

int main()
{
    vector<int> v;
    v.push_back(1);
    auto iter = find(v.begin(), v.end(), 1);  //iter指向的是数组中第一个元素
    cout << "iter所指元素的值:" << *iter << endl;
    cout << "容器容量capacity:" << v.capacity() << endl << endl;

    for (int i = 0; i < 10; i++)
    {
        v.push_back(666);
    }
    
    cout << "iter所指元素的值:" << *iter << endl;
    cout << "容器容量capacity:" << v.capacity() << endl;
    return 0;
}

运行结果:可以看到,iter迭代器一开始指向的元素是1,但是由于vector底层扩容,导致元素从一个空间迁移到另一个空间,原来的空间释放,iter指向了已经释放的内存(悬挂指针),从而导致结果出错。
在这里插入图片描述


场景重现2
  在我另一个项目里面使用到了unordered_map,但是和前面的迭代器失效不一样,这里是一个线程在执行find函数的时候,另一个线程插入元素,导致哈希表扩容rehash,从而原来应该在哈希表中的数据find不到出现错误。

  调用find函数的流程:哈希表每个元素可以看做是一个桶,下满挂着的是链表(或者是红黑树),调用find的时候首先会通过哈希映射找到对应的桶,然后在桶下面去遍历找对应的键,如果找不到就会返回umap.end();

#include <iostream>
#include <vector>
#include <list>
#include <deque>
#include <map>
#include <unordered_map>
#include <thread>
#include <algorithm>
using namespace std;

int main()
{
    // unordered_map线程不安全
    unordered_map<int, int> umap;
    umap[3] = 1;
    thread t1([&]()
    {
        for (int i = 0; i < 100000; i++)
        {
            auto iter = umap.find(3);
            iter->second = 3;
        } 
    });
    t1.detach();

    thread t2([&]()
    {
        for (int i = 10; i < 100000; i++)
        {
            umap[i] = i;
        } 
    });
    t2.detach();

    return 0;
}

  运行结果:可能会运行成功,但是有时候也会报段错误。使用gdb调试可以看到,在通过iter访问值的时候,会报错,但是3在umap中是一定存在的,我们一开始就已经初始化了键为3的值。
  原因:当一个线程在调用find函数的时候,通过哈希映射找到了桶的指针,此时另一个线程往umap中插入元素导致哈希表扩容rehash,每个桶指针从原来的内存迁移到另一个内存空间中,此时find继续往后找就会找到nullptr,于是就返回umap.end(),里面是一个空指针,通过空指针去访问变量自然会报段错误。

在这里插入图片描述


其他

   vector底层是连续的内存空间,除了扩容导致的迭代器失效,即使没有发生扩容,插入元素也会导致后面的迭代器失效,因为插入位置之后的元素都会向后移动,使得原来的迭代器不再指向原来的元素。删除也是同理,也会造成插入位置之后的迭代器都失效,同时删除位置的迭代器也会失效。
   list底层是不连续的内存空间,所以插入元素,扩容都不会导致迭代器失效,但是删除元素会导致指向删除元素的迭代器失效。

如何解决删除的时候迭代器失效的问题:

    for (auto iter = v.begin(); iter != v.end();)
    {
        if (*iter % 2 == 0)
        {
            iter = v.erase(iter);
        }
        else
        {
            ++iter;
        }
    }

  可以使用如上所示的方法,删除数组中所有的偶数,删除后erase会返回下一个元素的迭代器,用它重新赋值迭代器即可。

测试程序

#include <iostream>
#include <vector>
#include <list>
#include <deque>
#include <map>
#include <unordered_map>
#include <thread>
#include <algorithm>
using namespace std;

int main()
{
    vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    for (auto num : v)
    {
        cout << num << endl;
    }
    for (auto iter = v.begin(); iter != v.end();)
    {
        if (*iter % 2 == 0)
        {
            iter = v.erase(iter);
        }
        else
        {
            ++iter;
        }
    }
    cout << "***" << endl;
    for (auto num : v)
    {
        cout << num << endl;
    }

    return 0;
}

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/455056.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【AI帮我写代码,上班摸鱼不是梦】如何调教ChatGPT,让它帮我写程序。

最近发现磁盘空间严重不足&#xff0c;都弹窗提示我了&#xff1a; 想想看到底哪个文件夹占的空间比较大&#xff0c;好做针对性的删除和清理。奈何Windows系统没有查看文件夹大小的工具&#xff0c;只能鼠标放在某个文件夹上&#xff0c;等提示&#xff1a; AI时代都来临了&am…

AttributeError: ‘ChatGLMConfig‘ object has no attribute ‘quantization_bit‘解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

STM32 产生随机数方式

STM32 产生随机数方式 C语言的stdlib.h库里的srand(unsigned seed)和rand(void)函数&#xff0c;可以配合产生伪随机数。其中srand(seed)产生算法种子&#xff0c;再由rand()通过算法产生随机数&#xff0c;产生的随机数在宏定义RAND_MAX范围内。如果seed不变&#xff0c;则产…

测试从未如此简单:接口自动化测试Python脚本实现

目录 摘要 步骤1&#xff1a;安装依赖项 步骤2&#xff1a;编写测试脚本 步骤3&#xff1a;运行测试 结论 摘要 自动化测试是现代软件开发过程中的重要环节。在许多情况下&#xff0c;特别是在web应用程序和移动应用程序中&#xff0c;接口自动化测试是其基础。下面就来介绍一…

嵌入式就业怎么样?

嵌入式就业怎么样? 现在的IT行业,嵌入式是大热门&#xff0c;下面也要来给大家介绍下学习嵌入式之后的发展以及就业怎么样。 首先是好找工作。嵌入式人才目前是处于供不应求的状态中&#xff0c;据权威统计机构统计在所有软件开发类人才的需求中&#xff0c;对嵌入式工程师的…

详解树与二叉树的概念,结构,及实现(上篇)

目录 一&#xff0c; 树 1.2 树的相关概念 1.3 树的表示 1.4 树在实际中的运用&#xff08;表示文件系统的目录树结构&#xff09; 二&#xff0c; 二叉树 2.1二叉树概念 三&#xff0c;特殊的二叉树 1. 满二叉树 2. 完全二叉树 3. 1 二叉树的性质 3. 2 二叉树的存储…

北邮22信通:二叉树层序遍历的两种方法首发模板类交互

北邮22信通一枚~ 跟随课程进度每周更新数据结构与算法的代码和文章 持续关注作者 解锁更多邮苑信通专属代码~ 获取更多文章 请访问专栏~ 北邮22信通_青山如墨雨如画的博客-CSDN博客 目录 一.总纲 二.用队列存储 2.1用模板类实现队列 2.1.1核心思路&#xff1a; …

FL Studio电音编曲软件V21中文完整版 安装下载教程

目前水果软件最版本是FL Studio 21&#xff0c;它让你的计算机就像是全功能的录音室&#xff0c;大混音盘&#xff0c;非常先进的制作工具&#xff0c;让你的音乐突破想象力的限制。喜欢音乐制作的小伙伴千万不要错过这个功能强大&#xff0c;安装便捷的音乐软件哦&#xff01;…

PTA L2-045 堆宝塔 (25 分)

堆宝塔游戏是让小朋友根据抓到的彩虹圈的直径大小&#xff0c;按照从大到小的顺序堆起宝塔。但彩虹圈不一定是按照直径的大小顺序抓到的。聪明宝宝采取的策略如下&#xff1a; 首先准备两根柱子&#xff0c;一根 A 柱串宝塔&#xff0c;一根 B 柱用于临时叠放。把第 1 块彩虹圈…

掌握ChatGPT:全面指南和GPT-3.5与GPT-Plus的对比分析

在人工智能领域&#xff0c;最近的一大重磅炸弹是OpenAI发布了GPT-4架构下的ChatGPT。这款先进的自然语言处理模型已经引起了很多关注&#xff0c;让我们来深入了解怎么使用这个强大的工具&#xff0c;以及比较GPT-3.5与GPT-Plus的差异。 什么是ChatGPT&#xff1f; ChatGPT是…

JavaScript经典教程(三)-- JavaScript -- 基础数据类型详解

183&#xff1a;基础数据类型详解 1、复习 1、全局变量&#xff1a; 依托于window环境下的的变量。 在window大环境下&#xff08;即最外层&#xff09;申明的变量a&#xff0c;即为全局变量。 2、window&#xff1a; window下的变量为全局变量。 window可省略。 3、作用域…

021 - C++ 构造函数

我们继续学习 C 的面向对象编程&#xff0c;本期主要是讲其中的 构造函数。 什么是构造函数呢&#xff1f; 构造函数基本上是一种特殊类型的方法&#xff0c;它在每次实例化对象时运行。 我们直接来看一个例子吧。 例子时间 我们将要通过创建一个 Entity 类来深入了解这个…

vscode python3.6配置pcl点云库 obj3d模型转pcd点云图

配置vscode python3.6的环境我就跳过了,网上都有 1.下载PCL1.9 github:pcl-1.9.1 百度云:PCL-1.9.1-AllInOne-msvc2017-win64提取码adcx 2.安装硬盘任意位置,我是E盘,在安装过程中会弹出openni的安装提示,将它安装路径选择在E:\PCL 1.9.1\3rdParty\OpenNI2,等待安装完成 3.…

.netCHATING 10.4 for NET6-7.0-Crack

.NET 6.0图表支持--dotnetcharting .netCHATING 10.4添加了.NET 6.0图表nuget包和.NET 6.0图表示例包&#xff08;需要Visual Studio 2022&#xff09;&#xff0c;.NET 5是.NET Core 3.1和.NET Framework 4.8的继任者&#xff0c;旨在为.NET开发人员提供新的跨平台开发体验。…

Mysql列的类型定义(字符串类型)

文章目录 一、CHAR 类型和 VARCHAR 类型 1.字符串字符(M)2.实战类型二、TEXT 类型 1.类型表2.特别注意3.实战建议4.实战练习三、ENUM 和 SET 类型 1.ENUM类型2.SET类型总结 一、CHAR 类型和 VARCHAR 类型 CHAR类型和VARCHAR类型都在创建表时指定了最大长度&#xff0c;其基本形…

Java版工程行业管理系统源码-专业的工程管理软件-提供一站式服务

Java版工程项目管理系统 Spring CloudSpring BootMybatisVueElementUI前后端分离 功能清单如下&#xff1a; 首页 工作台&#xff1a;待办工作、消息通知、预警信息&#xff0c;点击可进入相应的列表 项目进度图表&#xff1a;选择&#xff08;总体或单个&#xff09;项目显示…

对数据结构的初步认识

前言: 牛牛开始更新数据结构的知识了.本专栏后续会分享用c语言实现顺序表,链表,二叉树,栈和队列,排序算法等相关知识,欢迎友友们互相学习,可以私信互相讨论哦! &#x1f388;个人主页:&#x1f388; :✨✨✨初阶牛✨✨✨ &#x1f43b;推荐专栏: &#x1f354;&#x1f35f;&a…

拿下多家车企定点!4D毫米波雷达「域」系统首发出道

从1R、2R、3R到整车360感知方案&#xff0c;毫米波雷达的前装市场需求量依然保持着快速增长的态势。 高工智能汽车研究院监测数据显示&#xff0c;2022年中国市场&#xff08;不含进出口&#xff09;前装标配搭载ADAS毫米波雷达&#xff08;前向后向盲区&#xff09;交付1795.…

mov是什么格式的视频,mov怎么转mp4

mov是什么格式的视频&#xff0c;MOV即QuickTime影片格式&#xff0c;它是Apple公司开发的一种音频、视频文件格式&#xff0c;用于存储常用数字媒体类型。MOV部分编码在没有quicktime的电脑中不能播放&#xff0c;不能后期剪辑制作MP4的通用率高于MOV格式支持MP4格式的播放器绝…

获得将要生成的资源的GUID

1&#xff09;获得将要生成的资源的GUID ​2&#xff09;多个小资源包合并为大资源包的疑问 3&#xff09;模型Meta中的hasExtraRoot参数的作用和历史原因 4&#xff09;合批注意点 这是第333篇UWA技术知识分享的推送&#xff0c;也是《厚积薄发 | 技术分享》第三回&#xff0c…