问题描述:
两个线程同时操作一个vector。线程A搜集数据,然后将数据push_back到vector里。线程B进行读取操作,循环vector查找所需结构体。然后根据下标,修改对应结构体中的数据。此时,系统弹出vector subscript out of range的错误。

问题分析:
因为出现这个问题的时候,我想的是多线程操作同一个vector,只要没有对元素进行删除的操作就应该没问题。因此,没有加锁。事实上,这是不正确的想法。也是我对STL容器不够熟练的一个体现。vector本质上是一个自动增长的数组。因此,每当vector的大小超过容量时,就会重新分配一个更大的容量,以便后续的元素增加。而这个增加容量的操作,并不是从vector的现有内存地址的后面增加,因为有可能后面的内存地址被占用了,而是从新的内存区域开辟新的内存空间。比如,你有一个保存整型int的vector。vector list(5,1)。这是一个包含5个1的vector。内存空间也应该是占了五个整型空间。举个例子就是,0x011到0x015。此时你再push_back一个新的元素6。我原本以为是这个元素6是会保存在地址0x016的位置上。而事实上不是,vector会重新分配空间。因此,有可能分配到的空间就是0x020到0x025。当多线程时,线程A正在重分配Vector空间。而线程B正在读取vector[1]的数据。本应该在0x012位置的数据。重分配空间后内存地址就会变为0x021。此时就会抛出异常v。 正因如此,我就踩进坑里面了。 这点也警醒了我,如果vector是不断后插数据的话,最好预先划分好空间。不然Vector从0开始增长会经历很多次的内存拷贝,导致性能下降。

技术分析:
这部分有参考C++Primer一书以及个人实际碰到问题后的思考。
1.书上的假设了一种情况:
假定容器中元素是连续存储的,且容器的大小是可变的,考虑向vector添加元素会发生什么:如果没有空间容纳新元素,容器不可能简单的将它添加到内存中其他位置-------因为元素必须连续存储。容器必须分配新的内存空间来保存已有元素和新元素,将已有元素从旧位置移动到新空间中,然后添加新元素,释放旧存储空间。如果我们每添加一个新元素,vector就执行一次这样的内存分配和释放操作,性能会慢到不可接受。为了避免这种代价,标准库实现者采用了可以减少容器空间重新分配次数的策略。当不得不获取新的内存空间时,vector和string的实现通常会分配比新的空间需求更大的内存空间。容器预留这些空间作为备用,可用来保存更多的新元素。这样,就不需要每次添加新元素的都重新分配容器的内存空间了。
PS:为什么整段写下来了,因为这个我自己思考的差不多,而且本来书上有的东西,怪自己看的不仔细掉进坑里,浪费了宝贵的时间,实在有必要记录下来。
2.vector的size和capacity
了解这两个之间的区别非常的重要。size指的是当前vector所包含的元素个数,而capacity指的是该vector最多能保存的元素个数。

 vector<int> list(5,1);list.size();        //5list.capacity(); //5list.push_back(1);   //6个元素list.size();      //5list.capacity(); //一般是10左右

3.通过代码记录这个错误
错误复现:复现这个错误,其实就是通过比较地址可以记录出来。因此代码采取的是查看第一元素的地址,比较地址是否改变就可以知道是不是访问了vector外的空间。

实践出真知,从该图就可以知道,当元素个数大于容量大小时。vector就会重新分配空间,而首地址也从010ED4B8变为010EBB40。而指针也不可访问该内存地址的值了。这就是vector subscript out of range的原因。

解决方案:
1.最简单粗暴的办法就是不用vector啦~
2.上锁,每个线程要对链表进行操作时,先上锁。
3.使用vector里的函数resize和reserve
二者的区别:
(1) resize是调整capacity大小以及增加了新的元素到vector中,看代码

不仅capacity增加了,size也增加了。这是因为resize会扩充容量,并且添加元素初始化这部分新增容量。如果是通过下标去改变一个大小固定的vector的话,可以用resize。切记,此时使用push_back还是会加大容量。因为元素个数size和容量capacity是相等,再新增元素又会扩容。
(2)reserve就是不新增元素,只分配容量。看代码

push_back之后,元素个数才从5变为6。因此,如果是大概知道元素个数的最大值的话,推荐用reserve分配好空间。这样就可以减少不必要的内存拷贝操作。

vector容器操作导致访问vector subscript out of range相关推荐

  1. C++vector容器-赋值操作

    vector赋值操作 功能描述: 给vector容器进行赋值 函数原型: 代码如下: #include <iostream> using namespace std; #include & ...

  2. vector容器中关于处理从非0位置开始赋值的操作

    一:前言 问题描述:我们想从下标非0的位置开始赋值, 那么我们需要两步骤:1.确定开启的vector容器的范围(eg: vector v(1000)) 2.在赋值的时候,不可以用push_back() ...

  3. vector容器的用法

    转自一篇博客^-^: 1 基本操作 (1)头文件#include<vector>. (2)创建vector对象,vector<int> vec; (3)尾部插入数字:vec.p ...

  4. 【C++ 语言】vector 容器 ( 容器分类 | vector 声明 | vector 初始化 | vector 容器元素增删查改 )

    文章目录 序列式容器 vector 简介 vector ( 向量 ) 头文件 vector ( 向量 ) 声明及初始化 vector ( 向量 ) 添加元素 vector ( 向量 ) 查询元素 ve ...

  5. STL之Vector容器

    一.初识Vector容器 学习目标1:学会往Vector容器中添加内置数据类型和Vector容器的遍历 示例: #include "iostream" #include <v ...

  6. C++ vector 容器

    文章目录 为什么要使用 vector 1.vector可以动态分配内存 2.vector重写了比较运算符及赋值运算符 3.vector便利的初始化 4. 以邻接表的方式**储存图** 基本函数实现 容 ...

  7. C++知识点17——使用C++标准库(顺序容器vector常用操作)

    C++STL中的容器类型分为两种,一种是顺序容器,另一种是关联容器,这两种容器之所以被划分,本质区别是顺序容器可以通过元素在容器中的位置进行访问及存储,而关联容器只能通过键来访问和存储元素 顺序容器常 ...

  8. C++:vector容器中使用pair该如何访问成员

    (显然,vector 的索引从 0 开始,这和普通数组一样.通过使用索引,总是可以访问到 vector 容器中现有的元素.) 如果是简单的访问vector里边的成员的话,是这样的: #include ...

  9. Vector使用报错:Expression:vector subscript out of range

    做题的时候遇到一个简单的排序题目: 一共有个学生,每个学生有两门成绩,主课成绩和副课成绩,先按照主课成绩排序,相同的情况下按照副课成绩排序,然后按照排序后的名单输出前名的名单: 这个题目确实很简单,却 ...

  10. vector容器与iterator迭代器

    vector容器 vector是同一种类型的对象的集合,每个对象都有一个对应的整数索引值.和string对象一样,标准库负责管理存储元素的相关内存.我们把vector称为容器,是因为它可以包含其他对象 ...

最新文章

  1. 眠眠interview Question
  2. 技术管理:带人和团队管理
  3. scrapy two
  4. 接口中默认方法和静态方法_接口中的默认方法和静态方法
  5. freemaker .flt文件自动换行的问题,map循环获取key和value
  6. 局部加权线性回归(Locally weighted linear regression)
  7. Control Flow - Containers
  8. LINUX编译opencore-amr
  9. java 文件上传终止_java文件上传
  10. 码力十足学量化|如何获取指数成分股及权重数据
  11. 中国书籍出版情况分析:2020年中国书籍出版总印数为65.2亿册(张),其中社科人文类占书籍94.8%[图]
  12. Cesium 关于相机的orientation 及 destination并制作地球动画
  13. git reset三种模式区别和使用场景(hard,soft,mixed)
  14. Ubuntu12.04 Skype4.2 提示Skype can't connect,安装Skype4.3
  15. 腾讯文档的表格设置行高
  16. 【RT-Thread Smart】ART-Pi Smart 开发板开箱及爱之初次体验
  17. 基于MATLAB的全局多项式插值法(趋势面法)与逆距离加权(IDW)法插值与结果分析
  18. YOLOv2---优图代码+实现细节
  19. python 读文件 如何从第二行开始
  20. 【面试经历】美团2020秋招测试开发一面二面

热门文章

  1. Chia 云P图 全套解决方案
  2. 一个寒门博士的论文后记:我还是没有能力让母亲安享晚年
  3. mysql中floor的用法_Mysql报错注入之floor报错详解
  4. 一款不错的Android环形进度条
  5. 2023面试题大全updating
  6. mscorsvw.exe进程占用CPU资料80%以上的原因
  7. android朋友圈九宫格图片尺寸,朋友圈图片尺寸多少厘米(附朋友圈发图技巧)...
  8. 一切过往皆序章,一切未来皆可期——2021给自己定个小目标:读完52本书
  9. 查看已下载的Docker镜像latest具体版本
  10. windows调节屏幕文字清晰度、锐度,屏幕字体模糊怎么办,屏幕字体不清晰