【C++STL】双向循环链表与其迭代器的深度剖析及实现(百字短文速通)

news2024/11/29 2:45:50

1,双向循环链表基本结构的实现(不包含需要迭代器的部分)

先用struct封装链表的节点,这里我们仅需要提供一个构造函数即可,并且构造函数必须提供缺省值,因为会有如下使用场景:new Node();此时需要默认构造函数,所以必须有缺省值。

在list类模版中,先typedef 一下,这样方便使用Node<T>,

成员变量是双向循环链表的哨兵位头节点。

接下来是一些基本的接口函数:

空构造:仅仅需要new一个哨兵位头节点出来,但是要记得保证双向循环结构

push_back:传入一个T,不过T也有可能是自定义类型,所以要用&,const可以接收const对象和非const对象。

迭代器区间构造:

构造函数:构造时填入n个x。

值得一提的是,这个构造函数有可能跟上面的迭代器区间构造发生冲突,比如说:

list<int> lt2(5,1); 中5和1一般会被编译器默认为是int类型,于是:

对于迭代器区间构造函数:InputIterator会被推演为int,这样的话两个形参的类型都是int。

对于本构造函数:模版参数推演之后,两个参数分别是size_t和int。

系统认为两个int形参类型更加匹配,所以会去调用迭代器区间构造。

而迭代器区间的这个操作:

*first相当于对int进行解引用,所以会报错:非法的间接寻址

箭头所指处也更能证明我们的想法。

而解决方法只有重载一个如下图的函数:

这样就会调用这个函数,而不是迭代器区间的构造函数。

2,迭代器的实现以及相关函数的补充

我们知道list的底层空间不是连续的,所以原生指针的++和--不能达到我们预想的结果,我们所需要的是:++的时候走到它的next,--的时候走到它的prev。

将迭代器实现成一个类模版,对++ --以及一些其他的运算符进行重载可以解决这个问题。

2,1迭代器的实现

基本结构:

typedef是为了让代码更简洁易懂

成员变量是一个节点的指针

至于除了T之外的两个模版参数Ref和Ptr ,接下来会进行解释捏

构造函数:

++重载:

--重载:

判断是否为同一个节点:

重载*(解引用):

这里的返回值为什么不直接写成T&呢?

因为除了普通的迭代器,我们还要使用const迭代器,那样的话,返回值就是const T& 了,而const迭代器跟普通迭代器的结构极其相似,只有返回值不同,所以为了防止代码冗余,尽量复用代码,这才引入了模版参数Ref来手动控制。

重载->:Ptr模版参数的引入同上,是为了手动控制T和T*

你没看错,->的重载就是这么奇怪,这个需要我们以特殊的眼光来看待:

迭代器定义operator->的原因是:

迭代器是像指针一样的东西,如果是原生指针,解引用就可以获得对象,如果是一个结构,想要得到结构里的成员变量,就需要通过->来获得,比如日期类:

所有类型重载->都要这样,算是个奇怪的模版吧,至少我觉得很奇怪。

2,2相关函数的补充

看,这里我们手动传模版参数就可以实现iterator和const_iterator

begin,end,cbegin,cend:

erase:

clear:复用erase

析构函数:复用clear();

拷贝构造和赋值运算符重载:

这里很简单,唯独有一点要说的是,

拷贝构造函数是借助构造函数和std::swap来实现的,swap后,tmp对象会调用析构函数自动析构,

考虑到这一点,我们必须对this指向的对象进行处理,要不然就会把一个野指针交换给tmp,析构的时候会出现内存问题的。

在此之前,我们的处理都是将类中的指针类型的成员变量置为nullptr,

比如string:

比如vector:

但是这次不一样了,因为析构函数的内部必然需要对链表进行遍历,一边遍历一边释放节点,而遍历就需要用到iterator,iterator一旦++就会对当前节点进行解引用找到下一个节点,如果将_head置空,就会对空指针进行解引用。

所以我们要搞一个最简单的链表结构——空链表,以便于析构。

insert:

返回新插入节点的迭代器是为了符合官方库,不必在意这里。

3,反向迭代器的实现以及相关函数的补充

3,1反向迭代器的实现

Iterator这个模版参数,传的是谁的迭代器,实现的就是谁的反向迭代器,至于Ref和Ptr,

跟上面解释的一样。

成员变量就是某个容器的正向迭代器

构造函数:

重载*:

没错,解引用反向迭代器返回的是前一个位置的数据,这是因为下图:

由于rbegin和rend的位置跟begin和end的位置对称,所以,如果解引用返回当前节点的数据的话,就会访问到_head中的随机值,必须返回前一个位置的数据才行。

重载->:

重载++--

判断是否为同一个节点:

3,2相关函数的补充

这里是要先typedef出const_reverse_iterator的,因为如果先typedef出reverse_iterator的话,下面就会出现歧义。

ps:拷贝构造函数往往要对成员变量进行初始化,以便于交换之后析构。

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

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

相关文章

crawler爬虫抓取数据

crawler爬虫实现 学习目标&#xff1a; 了解 crawler爬虫运行流程了解 crawler爬虫模块实现 1. crawler功能 初始化driver输入公司名称,并点击判断是否需要验证如果需要验证&#xff0c;获取验证图片并保存获取打码坐标点击验证图片判断查询结果选择第一条查询结果获取主要信…

电脑自带的录屏软件在哪?图文教学,教你如何快速录屏

很多小伙伴或许都听说过电脑有一款自带的录屏软件&#xff0c;但却不知道这款录屏软件在哪里。电脑自带的录屏软件在哪&#xff1f;其实很简单&#xff0c;如果你的电脑是Win10或者Win11的电脑&#xff0c;那么就可以使用电脑自带的录屏软件&#xff0c;一起跟着小编来看看吧。…

初次认识C++类

目录 前言&#xff1a; 面向过程和面向对象的区别&#xff1a; C语言&#xff1a; C&#xff1a; 类的引入&#xff1a; 类的定义&#xff1a; 类的权限&#xff1a; 类的作用域&#xff1a; 类的实例化&#xff1a; 类的大小计算&#xff1a; 空类或则只…

急速肝了一波ChatGPT,听说阿里面试题都没问题~

目录前言注册步骤&#xff1a;最后总结前言 互联网圈子里面ChatGPT现在实在是太火了&#xff0c;但是你还没用过&#xff1f;我只能说你OUT了&#xff0c;ChatGPT是什么呢&#xff1f; 由人工智能实验室OpenAI发布的对话式大型语言模型ChatGPT引爆中文互联网。它可以与人类轻松…

2022年ts学习记录

以下记录的是&#xff0c;我在学习中的一些学习笔记&#xff0c;这篇笔记是自己学习的学习大杂烩&#xff0c;主要用于记录&#xff0c;方便查找一、TS 是什么 &#xff1f;##1、简介TS&#xff1a;是TypeScript的简称&#xff0c;是一种由微软开发的自由和开源的编程语言。ts …

朗润外盘国际期货:SC原油市场情绪回暖领涨期市

今日值得回溯的三个行情&#xff1a;①SC原油主力合约今日收高4.23%&#xff0c;研报建议仍以震荡行情对待&#xff1f;②沪锡主力合约收涨3.20%&#xff0c;现在做多合适吗&#xff1f;③鸡蛋主力合约收跌1.32%&#xff0c;研报称这只是小幅回调。 【今日期市盘面概况】 整体…

深度学习 Day25——使用Pytorch实现彩色图片识别

深度学习 Day25——使用Pytorch实现彩色图片识别 文章目录深度学习 Day25——使用Pytorch实现彩色图片识别一、前言二、我的环境三、前期工作1、导入依赖项和设置GPU2、下载数据3、加载数据4、数据可视化四、构建CNN网络结构1、函数介绍2、构建CNN并打印模型3、可视化模型结构五…

Docker安装EalasticSearch、Kibana,安装Elasticvue插件

使用Docker快速安装部署ES和Kibana的前提&#xff1a;首先需要确保已经安装了Docker环境。 如果没有安装Docker的话&#xff0c;先在Linux上安装Docker。 有了Docker环境后&#xff0c;就可以使用Docker安装部署ES和Kibana了 一、安装ES 1、拉取EalasticSearch镜像 docker p…

SpringIOC之创建Bean的核心方法doGetBean

概述面向资源&#xff08;XML、Properties&#xff09;、面向注解定义的 Bean 是如何被解析成 BeanDefinition&#xff08;Bean 的“前身”&#xff09;&#xff0c;并保存至 BeanDefinitionRegistry 注册中心里面&#xff0c;实际也是通过 ConcurrentHashMap 进行保存。Spring…

强缓存与协商缓存

Ⅰ、http缓存 HTTP 缓存策略 分为 > 「强制缓存」 和 「协商缓存」 为什么需要 HTTP 缓存 呢 ? &#x1f447; 直接使用缓存速度 >> 远比重新请求快 缓存对象有那些呢 &#xff1f;&#x1f447; 「图片」 「JS文件」 「CSS文件」 等等 文章目录Ⅰ、http缓存Ⅱ…

Hi3559av100平台8路1080P/720P输入配置流程梳理

平台&#xff1a; hi3559av100 硬件连接&#xff1a; 8路YUV422 -> 4路 2lane MIPI -> hi3559av100 最终效果&#xff1a; 经过处理后&#xff0c;后端可以实现8路独立视频流处理&#xff1b; 可以自由和后级VPSS/VENC/VO等模块进行绑定和处理 前言&#xff1a; &…

Spring-整合Mybatis

Spring-整合Mybatis 6&#xff0c;Spring整合 6.1 Spring整合Mybatis思路分析 6.1.1 环境准备 在准备环境的过程中&#xff0c;我们也来回顾下Mybatis开发的相关内容: 步骤1:准备数据库表 Mybatis是来操作数据库表&#xff0c;所以先创建一个数据库及表 create database…

IDEA设置默认JDK、Maven版本问题汇总

遇到的问题&#xff1a;使用IDEA导入一个Maven多模块项目遇到关于JDK和Maven版本相关的问题&#xff0c;这里记录一下解决办法。如何修改当前项目JDK和Maven的版本&#xff1f;修改当前项目对应Maven版本&#xff1a;File -> Setting -> 搜索Maven修改JDK版本&#xff0c…

图像处理--OpenCV学习笔记

内容简介 OpenCV是应用广泛的开源图像处理库&#xff0c;包括基本的图像处理方法&#xff1a;几何变换&#xff0c;形态学变换&#xff0c;图像平滑&#xff0c;直方图操作&#xff0c;模板匹配&#xff0c;霍夫变换&#xff1b;特征提取和描述方法&#xff1a;理解角点特征&a…

Linux驱动开发基础__工作队列

目录 1 引入 2 内核函数 2.1 定义work 2.2 使用 work&#xff1a;schedule_work 2.3 其他函数 3 代码 3.1 gpio_key_drv.c 3.2 button_test.c 4 内部机制 4.1 Linux 2.x 的工作队列创建过程 4.2 Linux 4.x 的工作队列创建过程 1 引入 前面讲的定时器、下半部 task…

ASEMI整流模块MDQ100-16的优点是什么?

编辑-Z ASEMI整流模块MDQ100-16参数&#xff1a; 型号&#xff1a;MDQ100-16 最大重复峰值反向电压&#xff08;VRRM&#xff09;&#xff1a;1600V 最大RMS电桥输入电压&#xff08;VRMS&#xff09;&#xff1a;1700V 最大平均正向整流输出电流&#xff08;IF&#xff0…

【内网安全】——Linux提权姿势

作者名&#xff1a;白昼安全主页面链接&#xff1a; 主页传送门创作初心&#xff1a; 一切为了她座右铭&#xff1a; 不要让时代的悲哀成为你的悲哀专研方向&#xff1a; web安全&#xff0c;后渗透技术每日emo&#xff1a; 希望你在新的一年也能更好&#xff0c;不惧流言蜚语&…

Django drf使用Django自带的用户系统的注册功能实现

在写登录功能的时候看着网上的视频学着做,然后看了源码的时候发现了一些有意思的功能,因此写这一篇笔记分享给大家. 1.阅读Django自带用户系统源码 1.1 阅读User类源码 系统自带的用户系统的models文件的位置\site-packages\django\contrib\auth\models.py,打开这个文件发现…

python爬虫--re模块简介

Python re正则表达式模块用法详解 前面章节介绍了一些系统自带的工具函数&#xff0c;如 id()、max()。这些函数在 Python 启动时会自动加载进来&#xff0c;不需要我们做任何事情。但并不是所有的模块都是自动加载进来的&#xff0c;因为有些模块不常用&#xff0c;它们只是在…

记录一次web server服务器编程过程中的bug

按照书上和视频中的代码比对没有问题&#xff0c;但是read函数输出不了连接的http请求&#xff0c;不断编译了好几遍还是不行&#xff0c;确定是端口的问题 首先&#xff0c;在云服务器中安全规则里已经允许了相应端口&#xff0c;如果还不可以&#xff0c;可以查看一下系统防火…