c++迭代器的介绍

news2024/9/9 7:02:12

迭代器主要的作用就是为了可以像数组那样实现指针向后移动到下一个数据。同时迭代器统一了所有容器,让所有容器可以通过迭代器互通数据。

那么下面我们来看看迭代器

数组的优势

我们数组的优势就是内存连续,那么我们将首地址的地址进行加减就可以访问上一个数据和下一个数据:

大概就是得到开头的指针,然后得到最后一个数据的下一个指针,然后我们就可以用这种方法逐一操作数据了。

迭代器

此时我们稍微将这个指针包装一下:

这大概就是迭代器的大概意思。

iterator就是迭代器的名字,所用容器的迭代器都叫这个名字

迭代器将所有的容器都视为数组的“连续内存形式”,这样我们就可以使用指针的加减操作。

各种容器迭代器的使用方法

容器名::iterator

定义迭代器要指定是哪个容器的迭代器

因为不同容器的内存形式是不同的,像链表就是碎片化的内存,那么我们的迭代器为了实现“数组的形式”,就要实现一个类来重载++、--这些操作,就是模拟指向下一个节点,上一个节点。所以每个容器的迭代器底层是不同的,所以为了保证迭代器名字相同就要typedef 一下。所以迭代器是名字一样,实现目的一样,但是实现的过程不同。

这些不同底层的迭代器都是在每个容器的类里面定义的,所以要加上空间限制符来指定你现在是用的哪个类的迭代器

头尾迭代器的调用

迭代器的开始就是类.begin(),尾就是类.end()

举例:

string:

vector:

list:

这里面的迭代器都是指向内容的地址指针,解引用后才是所要的数据。

既然是获取到它的地址,那么我们可以用迭代器做很多事情。改变数据,获取数据都是很方便的。

迭代器的种类

每个容器内部迭代器分类

每个容器实现的迭代器作用是基本相同的。我们有时候不想要可以改变值的迭代器,所以就有了const_iterator类的迭代器,同时我们想要反向遍历的迭代器,所以有了reserve_iterator

iterator

上面做了详细的讲解,就是正向的迭代器。

const_iterator

为什么我们不直接用const iterator呢?

这里我们要这样看:用string的迭代器来举例,string的迭代器底层应该就是数组指针进行包装:

这样看就会明白,直接在iterator前面加const只是让它的地址不能改变。编译器会将iterator看成一个整体,所以只能修饰我们的p指针。

我们可以看到依旧可以改变值。

所以就要这样tyedef:(用string的举例)

typedef const char* const_iterator

这样就会修饰我们的*p(值)了。

这里还是用begin()的原因就是进行了重载,而编译器会根据你传入值的类型来匹配最合适的重载,因为这里要返回const_iterator类型的,所以会调用返回对应类型的begin函数。

reverse_iterator

我们可以用iterator来反着遍历吗:

我们end是指向最后一个数据的下一个指针,我们可以-1来调整到最后一个开始,但是我们的begin要怎么调整呢?-1就会报错。所以是不能反着来的。

所以就有了reverse_iterator

这里会接触到一个单词reserve(反转),要和reverse(预留)做区分。

具体的实现底层我还不知道,没学到那去。

这里的reverse_iterator就是将方向变了,原先的正方向掉了个头。现在想左是正方向。

那么也就有对应的函数来返回对应的开头和结尾迭代器rbegin rend,r就是reverse的第一个字母,联系记忆。

const_reverse_iterator

既然有了反向迭代器,那么也要考虑权限的问题,所以就有const_reverse_iterator:

只能读不能写。

容器间迭代器的分类

因为不同容器的内存形式不同,产生内存结构的局限性,所以我们的迭代器的功能不是完全一样的。

例如我们的单链表是不能逆序遍历的,只能正向便利,所以只有正向迭代器。又因为链表的内存的不连续性,所以不支持迭代器的加减,只支持自增自减。

所以就分了:

随机迭代器(RandomAccessIterator)

这种迭代器支持迭代器的加减:

因为它自身是连续内存,所以这样跳跃访问时间复杂度是O(1)。

双向迭代器(BidirectionalIterator)

这种迭代器不支持跳跃访问,因为内存的不连续,如果支持时间复杂度是O(N),将是很大的时间损耗。

但是可以双向移动,例如我们的双向链表。

单向迭代器(ForwardIterator)

这种迭代器不支持双向访问,只能一个方向访问,即正向访问。

例如单链表,就只能正向访问。

那么这样就可以用维恩图来看:

迭代器的失效问题

有些情况我们的迭代器在传入到某些函数里面后,迭代器就失效了,要么不可访问成为野指针,要么就已经不是指向所要指的值了。

这里我们用数组来举例:

例如我们有一个这样的数组,我们的一个模拟的数组迭代器指向1处。我们要在1前面插入一个数据'x',那么就会变成"0x123",但是我们的迭代器依旧指向第二个空间,所以如果我们再次访问这个地址,就会访问到'x'而不是原来的'2'。

还有很多失效的情况我就不一一举例,我们要根据各个容器的底层结构来分析,看看迭代器是否失效。

当然也有迭代器不失效的情况,例如list的插入就不失效,因为内存是不连续的,插入和删除操作不会影响每个节点。

总之我们尽量不要使用做了参量的迭代器,防止某个函数过后迭代器失效,或者我们接收一下函数返回值更新我们的迭代器值

迭代器互通的底层支持

首先像string这种连续内存的迭代器很好实现。但是像list这种的就需要额外创建一个迭代器类来进行实现:

重载和类

单独创建一个list_iterator类,然后用运算符重载来实现自增自减,还有比较重载,然后在类里面typedef一下:typedef list_iterator iterator,那么这个种类的迭代器就只能在这个类里面使用,除非你知道它原本迭代器的名字。

模板

我们会遇到一些全局函数可以传任意的迭代器:

例如上面这个实现容器元素逆置的函数,只要是双向类型及以上的迭代器都可以传给它进行数据的交换。这就用到了模板来进行支持。

看到最后点个赞吧🙂!

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

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

相关文章

【多线程】补充内容 {线程池;线程安全的单例模式;STL容器、智能指针的线程安全;其他常见的各种锁:自旋锁、读写锁}

一、线程池 1.1 概念 线程池一种线程使用模式: 线程过多会带来调度开销,进而影响缓存局部性和整体性能。 而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务:(线程池的优点) 这避免了在处…

将真实世界带入实验室—如何使用ALPS进行网络损伤仿真测试

不完美的真实世界网络 不同于稳定、可控的传统网络实验室的网络环境,真实世界的网络环境面临着许多挑战和风险,这些挑战在很大程度上增加了网络的脆弱性和复杂性: (1)物理损伤:真实世界的网络基础设施&am…

Java扫码点餐系统奶茶店类型堂食配送小程序源码

🥤【奶茶新风尚!扫码点餐系统,堂食配送两不误】🥤 🏠【堂食新体验:一键下单,即享美味】🏠 踏入心仪的奶茶店,不再需要排队等候点单,只需拿起手机&#xff0…

TongHttpServer 简介

1. 概述 随着网络技术的飞速发展,高并发大用户场景越来越普遍,单一应用服务节点已经不能满足并发需求,为了提高整个系统可靠性,扩展性,吞吐率,通常将多个应用服务器通过硬负载/软负载组成集群,负载均衡器根据不同负载算法将请求分发到各个应用服务器节点。 Tong…

飞书打卡 快捷指令

使用快捷指令定时飞书打卡 在网上找了一圈,只有钉钉打卡的快捷指令,但是公司换飞书,哪个打工人不怕忘记打卡呢,所以自己研究了一下,其实也很简单。 找url 问题的最关键是打开飞书的打卡界面 如果只是打开飞书APP 很…

手动上电电路(电路收藏)

SW1按下 V1栅极对地 V1通 Vout给Mcu工作 GPIO2 高电平 V2通 SW1松开 V1栅极依然通过V2对地 维持V1通 Vout。再次按下SW1 GPIO1 对地 使Mcu收到中断 将GPIO2 输出低电平 V2关 松开SW1 V1栅极悬空 V1断开 Vout被截断

大数据基础:Spark重要知识汇总

文章目录 Spark重要知识汇总 一、Spark 是什么 二、Spark 四大特点 三、Spark框架模块介绍 3.1、Spark Core的RDD详解 3.1.1、什么是RDD 3.1.2、RDD是怎么理解的 四、Spark 运行模式 4.1、Spark本地模式介绍 4.2、Spark集群模式 Standalone 4.3、Spark集群模式 Stan…

中国十大顶级哲学家,全球公认的伟大思想家颜廷利:人类为何拥有臀部

人类为何拥有臀部?若众生皆无此部位,又如何能寻得一处真正属于自己的“座位”?在博大精深的中国传统文化中,汉字“座”与“坐”均蕴含“土”字元素。在易经的智慧里,作为五行之一的“土”,象征着人类社会的…

将gitee 上的nvim 配置 从gitee 上下载下来,并配置虚拟机

首先是下载 gitee 上的配置。 然后是 配置 tmux 然后是配置nvim . 1 在init.lua 文件中注释掉所有的与第三方插件有关的内容。 2 在packer 的文件中 , 注释掉所有的与 第三方插件有关的代码。 3 首先要保证 packer 能够正确的安装。 4 然后开始 安装 所有的插件…

汇川技术|CANlink、CANopen、Profibus-DP网络编辑器的使用

哈喽,你好啊,我是雷工! 本节学习CANlink、CANopen、Profibus-DP网络编辑器的使用。 以下为学习笔记。 01 CANlink编辑器 在AC810的【网络组态】中未看到CANlink主站的功能,所以先简单了解,等具体使用时再具体查看。 …

2024最全RabbitMQ集群方案汇总

之前在网上找rabbitmq集群方案有哪几种时,基本上看到的答案都不太一样,所以此文的主要目的是梳理一下rabbitmq集群方案,对rabbitmq集群方案的笔记并不是搭建的笔记。 总结了一些文章,rabbitmq集群大概有五种方案:普通…

一文搞懂网络IO和java中的IO模型

目录 1.绪论 2.IO分类 3.用户空间和内核空间 4.同步阻塞IO 5.同步非阻塞IO 6.IO多路复用 6.1 基本原理 6.2 linux对IO多路复用的实现方式 6.3.1 select 1.实现原理 2.缺点 6.3.2 poll 1.实现原理 6.3.3 epoll 1.epoll数据结构 2.epoll的函数 3.epoll的优点 4…

【实践出真知】使用Docusaurus将md文档组织起来就是一个网站(写API文档,写教程、写日记、写博客的有福了)

文章目录 前言一、Docusaurus 是什么?二、一键生成网站框架并预览1. 系统需求2. 脚手架项目网站(一键生成网站框架)3. 生成的目录内容4. 网站运行与展示 总结 前言 前段时间,学习Flet,访问到Flet中文网,被…

魔方财务新版QRuser用户中心主题

本主题支持魔方财务3.5.7版本!可自由切换魔方财务3.5.7版本与其他版本。本主题基于官方default开发,主要面向企业,三端自适应,支持并完美适配多语言。界面精美,简洁清新,主题内新增多处bootstrap-select的调…

软考系统架构师-计算机网络基础

目录 3.1 网络的基本概念 3.2 通信技术 3.3 网络技术 3.4 组网技术 1.网络设备及其工作层级 2.网络协议 (1)应用层协议。 (2)传输层协议。 (3)网络层协议。 3.交换机 4&#xff0e…

Speckly:基于Speckle文档的RAG智能问答机器人

前言 Speckly 是一个基于 检索增强生成 (RAG) 技术的智能问答机器人,它能像一位经验丰富的工程师,理解你的问题,并从 Speckle 文档中精准地找到答案。更厉害的是,它甚至可以帮你生成代码片段! 🚀 本文将详…

linux:基本权限

1、权限与用户之间的关系 在Linux系统中,针对文件定义了三种身份,分别是属主(owner)、属组(group)、其他人(others),每一种身份又对应三种权限,分别是可读(readable)、可写(writable)、可执行(excutable)。 2、如何修改一个文件的…

快团团等社区团购类小区物资团购怎么按商品批量退款?

疫情期间,小区物资团的配送需要达到一定的起送件数,对于一些没有达到起送件数的商品,如何快速地批量退款呢?按照下列操作,只需四步,就可以对某一商品批量退款。 第1步:进入团购页面&#xff0c…

JavaScript(二)变量

一、两种注释方式 // 这是当行注释/* 这是多行注释 这是多行注释 */二、变量是什么 变量就是一个可以存放“数值”的容器,这个“数值”可以是数字、字符串、函数等。 变量不是数值本身,它是一个用于存储数值的容器,你可以把变量想象成一个个…

解决断点问题导致项目没有完全启动bug

场景: 项目启动正常,启动日志也正常打印,但是无法判断是否启动完毕,访问接口也进不了服务 原因: 启动前调试项目打断点时 不晓得打到了某个层面的断点 具体是哪忘了,导致项目没有完全启动,启…