【C++】-vector的具体使用(迭代器失效问题)

请添加图片描述
💖作者:小树苗渴望变成参天大树🎈
🎉作者宣言:认真写好每一篇博客💤
🎊作者gitee:gitee✨
💞作者专栏:C语言,数据结构初阶,Linux,C++ 动态规划算法🎄
如 果 你 喜 欢 作 者 的 文 章 ,就 给 作 者 点 点 关 注 吧!

文章目录

  • 前言
  • 一、文档介绍[vector](https://legacy.cplusplus.com/reference/vector/vector/?kw=vector)
    • 1.1vector的接口
    • 1.2vector构造器
    • 1.3vector遍历和修改数据操作
    • 1.4vector的空间增长问题
    • 1.5vector的插入和删除操作
    • 1.6vector的排序操作
    • 1.7vector的查找操作(迭代器失效)
  • 二、总结


前言

今天我们开始讲解新的知识,关于vector的使用,这个容器使用起来非常的香,他可以做很多事情,也类似于一种数组的实现,但是他比数组更加的高级,让我们一起来看看vector是怎么使用的吧


一、文档介绍vector

在这里插入图片描述
对于vector我们目前可以简单理解为存放任意类型的可变数组。也可以像数组那些去使用,但是又被数组的用法多。

1.1vector的接口

想要学会vector的使用,我们需要熟悉它的接口,他能更好的运用它,接下来我就带大家来学习再常用的接口以及使用方法
在这里插入图片描述
通过文档我们发现vector实现了这些的接口,有些接口大家看到应该就东什么意思,因为我们刚刚学会string类,接口名都是一样的,我们想要使用一个容器,就必须先实例化出对象,就要先掌握它对应的构造器

1.2vector构造器

在这里插入图片描述
来看看这几种构造器的使用:

	//1.默认构造器vector<int> v1;//2.初始化的值要符合定义的类型vector<int> v2(4,100);//3.使用迭代器或者指针都行string s;int a[4] = { 0 };vector<int> v3(s.begin(), s.end());vector<int> V3(a,a+4);//4.用另一个vector对象创建另一个vector<int> v4(v3);

我们一共就这四种,再下篇的模拟实现中,我会带大家都实现一遍,让大家体会里面的原理

1.3vector遍历和修改数据操作

(1)iterator
在这里插入图片描述
我们迭代器的种类非常多,博主就介绍其中一种,其余的使用是类似的,这个迭代器的使用和前面string使用迭代器是一样的

	vector<int> v2(4, 100);vector<int>::iterator it = v2.begin();while (it != v2.end()){cout << (*it)*=2<<" ";it++;}cout << endl;

(2)operator[]下标的方式
就是遍历数组一样的道理

vector<int> v2(4, 100);for (size_t i = 0; i < v2.size(); i++){v2[i]=20;cout << v2[i] << " ";}cout << endl;

(3)范围for
通过前面string的学习,我们知道范围for是基于迭代器的存在去使用的,既然我们有了迭代器的存在,那看看范围for怎么使用

vector<int> v2(4, 100);for (auto& i : v2){i=50;cout << i << " ";}cout << endl;

我们还是喜欢下标的方式来遍历vector,毕竟用的时候最长。

1.4vector的空间增长问题

在这里插入图片描述
对于接口什么意思我就不做过多的解释了,和string类的意思一样,直接来看使用

vector<int> v2(4, 100);cout << "一开始的size:" << v2.size() << endl;cout << "一开始的capacity:" << v2.capacity() << endl << endl;cout << "进行resize改变有效字符个数"<<endl;v2.resize(6);cout << "resize(6)后的size:" << v2.size() << endl;cout << "resize(6)后的capacity:" << v2.capacity() << endl << endl;cout << "进行reserve改变容量" << endl;v2.reserve(15);cout << "reserve(15)后的size:" << v2.size() << endl;cout << "reserve(15)后的capacity:" << v2.capacity() << endl << endl;cout <<"empty的测试:" << v2.empty() << endl;

在这里插入图片描述

注意: 我们来看一段代码

vector<int> v1;v1.reserve(10);for (size_t i = 0; i < 10; i++){v1[i] = i;}for (size_t i = 0; i < v1.size(); i++){cout << v1[i] << " ";}cout << endl;

在这里插入图片描述
我们一开始创建一个vector对象是没有空间的,我们进行扩容之后,想给将vector里面的数据改成0-9,结果运行却崩溃了,原因是:使用[]来进行访问vector里面的数据会有检查,是通过size的范围来确定的,通过上面的演示,你改变capacity的值,并不会改变size的,但是改变size的值有可能改变capacity的值,所以将reserve换成resize就可以了
在这里插入图片描述

使用迭代器和范围for都不行,他们的终点都是以size为准的

对于扩容每个平台的机制也是不一样的,再vs上市1.5倍扩容,再Linux上是二倍扩容,这个大家下去可以自己测试一下

1.5vector的插入和删除操作

在这里插入图片描述

我们发现有尾插和尾删,也有任意位置的插入和删除,再底层尾插和尾删是复用任意认知的插入和删除,再模拟实现·的时候再给大家介绍吧,我们先来看看这几个怎么使用吧。

对于push_back和pop_back

	vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);v1.push_back(6);for (size_t i = 0; i < v1.size(); i++){cout << v1[i] << " ";}cout<<endl;v1.pop_back();v1.pop_back();for (size_t i = 0; i < v1.size(); i++){cout << v1[i] << " ";}

在这里插入图片描述
对于insert
在这里插入图片描述

  1. 第一种传一个迭代器表示再vector的哪个位置插入一个元素
	vector<int> v1;v1.insert(v1.begin(), 1);v1.insert(v1.begin(), 2);v1.insert(v1.begin(), 3);v1.insert(v1.begin(), 4);v1.insert(v1.begin(), 5);v1.insert(v1.begin(), 6);for (size_t i = 0; i < v1.size(); i++){cout << v1[i] << " ";}

在这里插入图片描述

  1. 第二种传一个迭代器表示再vector的哪个位置插入n个元素
	v1.insert(v1.begin(), 1,100);v1.insert(v1.begin(), 2,200);v1.insert(v1.begin(), 3,300);v1.insert(v1.begin(), 4,400);v1.insert(v1.begin(), 5,500);v1.insert(v1.begin(), 6,600);for (size_t i = 0; i < v1.size(); i++){cout << v1[i] << " ";}

在这里插入图片描述

  1. 第三种是传其他迭代的中间的元素插入到任意位置
	vector<int> v1(4,100);int a1[4] = { 1,2,3,4 };v1.insert(v1.begin() + 1, a1 + 1, a1 + 3);for (size_t i = 0; i < v1.size(); i++){cout << v1[i] << " ";}

在这里插入图片描述

把数组的第二和第三个元素插入到vector的第一个元素后面

对于erase
在这里插入图片描述

  1. 第一种是任意位置的元素
vector<int> v1(4, 100);
v1.erase(v1.begin());
  1. 第二种是从first位置开始删除到last位置
vector<int> v1(4, 100);
v1.erase(v1.begin()+1,v1.begin()+3);

这两种非常简单,我就不做运行演示了

1.6vector的排序操作

我们的vector也可以进行排序,它有对应的算法sort函数,对应的头文件是 < algorithm >
在这里插入图片描述
因为sort不是给单独的一个容器进行使用的,所以不能当成vector本身的成员函数,来看看vector怎么进行排序:

升序:

	vector<int> v1;v1.push_back(1);v1.push_back(3);v1.push_back(4);v1.push_back(6);v1.push_back(5);v1.push_back(0);for (size_t i = 0; i < v1.size(); i++){cout << v1[i] << " ";}cout << endl;sort(v1.begin(), v1.end());for (size_t i = 0; i < v1.size(); i++){cout << v1[i] << " ";}

在这里插入图片描述

降序:
(1)这就要看我们第二个sort函数了,第三个参数是仿函数
我们定义仿函数greater<int> ggreaer具有大于的意思,前面一个比后面一个大,哪不就是降序吗??
在这里插入图片描述

(2)反向迭代器
在这里插入图片描述
通过仿函数和反向迭代器也可以实现升序,大家下来自己测试看看

1.7vector的查找操作(迭代器失效)

我们的查找函数也不是vector特有的函数,查找函数也和sort一样再算法里面,我们来看看文档里面怎么描述的
在这里插入图片描述
在这里插入图片描述

要注意:找的到就返回对应的迭代器,找到就返回此迭代器的下一个位置,迭代器都是左闭右开的,所以找不到是返回的pos=v.end()

代码演示:

	vector<int> v1;v1.push_back(1);v1.push_back(6);v1.push_back(4);v1.push_back(5);v1.push_back(3);v1.push_back(0);/// <summary>///我们尝试找到元素6然后删除vector<int>::iterator pos = find(v1.begin(), v1.end(),6);v1.erase(pos)for (size_t i = 0; i < v1.size(); i++){cout << v1[i] << " ";}

在这里插入图片描述

我们来看如果有多个重复的数字呢??

在这里插入图片描述
我们为了增加效率每次就不从头开始找了,我们发现上面这个带啊吗运行后,就会崩溃,为什么会这样呢??原因就是迭代器失效了


为什么会出现这种情况呢??原因是迭代器的主要作用就是让算法能够不用关心底层数据结构,其底层实际就是一个指针,或者是对指针进行了封装,比如:vector的迭代器就是原生态指针T* 。因此迭代器失效,实际就是迭代器底层对应指针所指向的空间被销毁了,而使用一块已经被释放的空间,造成的后果是程序崩溃(即如果继续使用已经失效的迭代器,程序可能会崩溃)。
对于vector可能会导致其迭代器失效的操作有:

  1. 会引起其底层空间改变的操作,都有可能是迭代器失效,比如:resize、reserve、insert、assign、push_back等。因为一发生扩容行为就会释放之前的空间,开辟一个新的空间。

有的人说我先把空间开的足够大,只要不扩容不就行了,可以说是可以的,但是危险性太大了,万一再公司程序有天数据变得很大,还是要扩容,那个时候再修改就来不及了

那我们刚才的代码是删除,不存在扩容的情况啊,为什么也会造成迭代器失效的问题呢???erase删除pos位置元素后,pos位置之后的元素会往前搬移,没有导致底层空间的改变,理论上讲迭代器不应该会失效,但是:如果pos刚好是最后一个元素,删完之后pos刚好是end的位置,而end位置是没有元素的,那么pos就失效了。因此删除vector中任意位置上元素时,vs就认为该位置迭代器失效了。

解决办法: 在使用前,对迭代器重新赋值即可
细心读者应该发现,我上面提到的那些可能会出现迭代器失效的接口都有一个迭代器接口,这个返回值就是新空间的迭代器,前面的代码这样修改就行了:

auto pos = find(v1.begin(), v1.end(),6);while (pos != v1.end()){v1.erase(pos);pos= find(pos+1, v1.end(), 10);}

现在和大家说这个问题大家应该可以理解,等博主实现模拟实现的时候,再好好跟大家说说,下一篇我将讲解两个题目,让大家看看vector的好处,再下下篇讲模拟实现

二、总结

相信大家对vector的基本使用都掌握了,后面我将会带大家把上面的函数都模拟实现一遍·,这样大家就能更好的理解底层是怎么处理问题的。我们今天的内容就先讲到这里。
请添加图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ipa上架App Store【uniapp-ios】

前置条件&#xff1a;已获取到.mobileprovision描述文件、.p12证书并打包生成ipa包 &#xff08;如果还没获取证书、描述文件等可以去看我前两篇博客&#xff1a;uniapp-ios打包步骤 、uniapp-ios打包安装测试。一篇是已经付费了即已经注册了Apple Developer Program&#xf…

【网络安全带你练爬虫-100练】第8练:json数据的最小项提取

目录 一、目标1&#xff1a;爬取指定json中数据 二、目标2&#xff1a;循环取json中数据 三、目标3&#xff1a;提取每个数据中的某一项 四、网络安全小圈子 一、目标1&#xff1a;爬取指定json中数据 爬取data里数据 核心代码&#xff1a; dirt1 json.loads(res.text)pr…

哪家好用?四款国内外远程桌面软件横测:ToDesk、向日葵、TeamViewer、AnyDesk

一、前言 远程桌面软件对于职场人来说并不陌生&#xff0c;可以说是必备的办公软件之一。在经历过新冠疫情后&#xff0c;大家对于远程办公的认识越来越深入&#xff0c;也就在这段期间&#xff0c;远程桌面软件大范围的应用起来&#xff0c;真正走进大众视野并融入我们的工作和…

一纸文书之MySQL的回忆录

MySQL要点学习&#xff1a;你可以在简历上说熟悉MySQL 什么是数据库&#xff1f;什么是数据库管理系统&#xff1f;什么是MySQL&#xff1f;什么是SQL&#xff1f;数据库数据库管理系统&#xff1a;SQL&#xff1a;结构化查询语言三者之间的关系 安装MySQL数据库管理系统MySQL常…

【软件分析/静态分析】chapter6 课程08 指针分析(Pointer Analysis)

&#x1f517; 课程链接&#xff1a;李樾老师和谭天老师的&#xff1a; 南京大学《软件分析》课程08&#xff08;Pointer Analysis&#xff09;_哔哩哔哩_bilibili 目录 第六章 指针分析&#xff08;Pointer Analysis&#xff09; 6.1 为什么需要指针分析 6.2 指针分析的基本…

惊!ChatGPT处理文章仅需一秒钟,提取大纲、重写不在话下!

前言 在上篇文章中&#xff0c;我们实现了批量抓取到微信公众号文章的链接地址&#xff0c;那么这篇文章将继续为大家介绍&#xff0c;如何根据链接爬取到文章内容&#xff0c;并且利用chantGPT对文章进行处理。 爬取文章内容 我们已经有了很多文章的链接&#xff0c;这些链…

C# 使用HttpListener时候异常(此平台不支持此操作:System.PlatformNotSupportedException)

C# 使用HttpListener时候异常&#xff08;此平台不支持此操作&#xff1a;System.PlatformNotSupportedException&#xff09; 代码&#xff1a; HttpListener listener new HttpListener(); 错误&#xff1a; System.PlatformNotSupportedException: Operation is not su…

(四)Kafka 消费者

文章目录 1. Kafka 消费者相关概念消费者和消费者组&#xff08;1&#xff09;横向伸缩消费者&#xff08;2&#xff09;横向伸缩消费者组 分区再平衡再均衡的类型&#xff08;1&#xff09;主动再均衡&#xff08;2&#xff09;协作再均衡&#xff08;增量再均衡&#xff09; …

Kubernetes对象深入学习之二:细说schema.ObjectKind

欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码)&#xff1a;https://github.com/zq2599/blog_demos 在前文咱们对对象体系有了大概了解&#xff0c;接下来就要按照前面换分的三个知识区域逐个深入学习&#xff0c;今天从最简单的对象类型开始 runtime.Object…

C语言 数组

1. 数组的地址 1.1 一维数组的地址 int a[5];&#xff08;1&#xff09; &a[0]第0个元素的地址a第0个元素的地址&a整个一维数组的地址 &#xff08;2&#xff09;&a[0] a &a&#xff1b; &#xff08;3&#xff09; &a[0] 1跳过一个数组元素a …

Gradio库中的Model3D模块:实时上传和展示3D模型

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️ &#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

如何与ChatGPT愉快地聊天

原文链接&#xff1a;https://mp.weixin.qq.com/s/ui-O4CnT_W51_zqW4krtcQ 人工智能的发展已经走到了一个新的阶段&#xff0c;在这个阶段&#xff0c;人工智能可以像人一样与我们进行深度的文本交互。其中&#xff0c;OpenAI的ChatGPT是一个具有代表性的模型。然而&#xff0…