C++——list(2)

作者:几冬雪来

时间:2023年9月28日

内容:C++——list内容讲解

目录

前言: 

list的const迭代器: 

const的iterator: 

const迭代器: 

operator->: 

拷贝构造:

迭代器接口补充: 

代码: 

结尾: 


前言: 

在上一篇博客中我们讲解了list的新接口,list与vector,string的区别所在。更加进一步的说明了list的迭代器的书写,而在今天我们将借由list迭代器来对list的const迭代器进行详细的讲解与说明。 

list的const迭代器: 

在学习list的const迭代器之前,我们先来回顾一下list的迭代器。

list,string和vector的迭代器访问的是指针,所以所有的容器都希望提供像指针一样去访问容器的方式。 

在string和vector只需要提供原生指针即可。

string和vector使用的原生指针,在这里typedef T*就是iterator,因为普通的指针完美的符合这个行为

并且string和vector的物理空间是连续的

因此它的解引用访问的就是该处的数据,进行++就是访问下一个数据。 

const的iterator: 

那么在这里,const的iterator是什么,它使用的指针和vector,string有什么不同

相较于二者,const的iterator有所不同。 

在const的使用中分为两种,一种是指针不能被修改,另外一种是指向的内容不能被修改

像上图在*之前的const修饰的都是指向的内容不能被修改,都是它自己是可以被修改的。所以的迭代器都要符合

string和vector的不同是因为二者的底层结构占了便宜,因为它们的空间是连续的,而list则是不连续的

const迭代器: 

在list中因为空间是不连续的,因此它的指针不能直接使用。这个时候就要借助一个类来封装,来控制它的行为。 

那么如果控制它的行为呢?我们可以重载它的operator*和operator++,这样就能控制它这里的行为

在这里我们就将封装的迭代器类型进行一个typedef来达到我们的目标

接下来我们进行讲解const迭代器,这里我们要使用的const是指向的内容不能被修改,而它自己本身是可以被修改的。 

这个地方很多人都会这样去写。 

普通迭代器的对象前加上一个const,这里的const影响的是我们的对象,对象不能被修改。因此在后面运行代码的时候就不能调++等操作。 

既然这条路走不通,那么我们该如何实现呢?这个地方就需要去控制operator*来达到这个目的

为了解决问题,在定义处我们又定义了一个新的类,这个新的类和原先的类基本一致。唯一有不同的点就是在operator*处

那么是哪个地方不同,我们就来对比一下。 

对比两个类中的operator*,我们不难看出二者的返回值不一样,新的类对比原先的类,在返回值处多了一个const

但是如果真的要这样写的话,那就太冗余了。 

这里有没有什么好办法呢?是有的,在这里我们可以通过一个类型去控制这个返回值,也就是增加一个模板参数。 

类似这里,我们就添加了一个模板参数,同时将operator*的返回值更改为Ref。那么这里的Ref是什么呢

从上面的类模板中我们是不知道的,这个时候就要看下面的iterator的书写了。

在这个地方普通的iterator的Ref代表的是T引用,而const iterator在这个地方则是代表的const T引用。 

这也就完成了想要的通过一个类模板给不同的实例化,其实这里本质上我们还是写了两个类,因为我们给了不同的模板参数

同时因为是不同的类,因此原先的类就不能使用了,在这个地方就需要我们对新的类进行typedef一下

这里将新的类typedef为self,同时在下面operator++和operator*等涉及到这个返回值的都要对其进行修改

operator->: 

接下来来讲解一下list中的operator->接口

这个地方有人就要问了,在我们还在学C语言的时候不是有讲解过->和&之间的关系,虽然书写的代码不同,但是结果是相同的。

在list迭代器中刚刚书写了解引用的操作,为什么还要加入->? 

为了解答问题,在这里我们写了一个链表,链表的类型是自定义类型。然后接下来我们要对类型进行访问。 

然后来看一下访问的代码。 

在这里我们迭代器模拟的是一个指向结构的指针。 

因为上面迭代器的类型是自定义类型,因此这个地方数据模拟的就是自定义类型的指针。所以代码就要用到->了。 

因此上面的这一串代码就能改编为下面这样。

而因为在这里使用了->,所以在迭代器中我们要加入operator->来辅助我们完成

那么再将它的代码写出来。

先比较与我们operator解引用时候书写的代码,operator->明显有着不同之处。首先是返回值,解引用的返回值是Ref,而->的返回值是T*

同时二者return的内容也是不同,->与解引用相比多了一个&符号

这两种情况就导致了operator->的返回值略显奇怪。

根据上图进行解释。 

operator*和operator->处return的_node->_val的值都是我们这里自定义类型A。但是因为返回值的不同,解引用的代码可以装换为对A的解引用,然后就能访问它里面的值

operator->不同,它的返回值是T*转换的结果是A*也就是A的指针,而我们没办法通过A*去访问A里面的值

因此理论上来说正确的代码应该这样写。 

这个地方需要两个->才能真正访问我们里面的数据,第一个->是去调用operator->返回的是A*, 然后第二个->就是去访问A里面的值

但是如果是这样书写的话,可读性极差。而我们的运算符重载正好要求可读性,那么编译器就进行了一个特殊处理,在这里省略了一个->

那么接下来一个问题就是它的const该怎么写,案例来说这里的返回值是const T*。 

 

解决这个问题的话,我们可以新增加一个模板参数来区分它们。 

拷贝构造:

接下来我们来讲解list的拷贝构造

通过两篇博客我们可以发现list的迭代器和vector与string多多少少有些不同,但是它们有一点是相同的,那就是在拷贝构造的时候都会出现深浅拷贝的问题。 

为了处理深浅拷贝的问题,在这个地方如果要将lt1给lt2,首先就要开空间,给出各个指向的是什么

开好空间之后,接下来就要遍历数据了。在这个地方有一个要注意的点,那就是正常情况下因为不清楚T的对象不确定是vector,string还是其他的,因此在遍历条件处要加引用操作符。 

最后再将lt1里面的数据插入到lt2,这样就能完成我们的深拷贝了。 

同样的我们也可以对我们的代码进行优化。 

因为在list迭代器中多次运用到开空间的操作,因此我们可以将它单独拿出来写一个接口,方便以后的调用。 

迭代器接口补充: 

再在最后,将我们平时迭代器用到的代码,比如erase,insert等等都写上,到这里我们的迭代器就正式完成了。 

代码: 

using namespace std;
#include<>
#pragma once  
#include<assert.h>namespace bit
{template<class T>struct list_node{list_node<T>* _next;list_node<T>* _prev;T _val;list_node(const T& val = T()):_next(nullptr),_prev(nullptr),_val(val){}}; template<class T,class Ref,class Ptr>struct __list_iterator{typedef list_node<T> Node;typedef __list_iterator<T, Ref> self; Node* _node;__list_iterator(Node* _node):_node(node){}   iterator begin(){return _head->_next;}iterator end(){return _head;}Ref operator*(){return _node->_val;}self& operator++(){_node = _node->_next;return *this;}Ptr operator->(){return &_node->_val;}self operator++(int){self tmp(*this);_node = _node->_next;return tmp;}self& operator--(){_node = _node->_prev;return *this;}self operator==(int){self tmp(*this);_node = _node->_prev;return tmp;}bool operator!=(const Ref& it){return _node != it._node;}bool operator==(const Ref& it){return _node == it._node;}};template<class T>class list{typedef list_node<T> Node;public:typedef __list_iterator<T, T&, T*> iterator;typedef __list_iterator<T,const T&, const T*> const_iterator;/*typedef const __list_iterator<T> const_iterator;*/list(){empty_init()}~list(){clear();delete _head;_head = nullptr;}void empty_init(){_head = new Node;_head->_next = _head;_head->_prev = _head;}list(const list<T>& lt){empty_init();for (auto& e : lt){push_back(e);}}void swap(list<T>& lt){std::swap(_head, lt._head);std::swap(_size, lt._size);}list<T>& operator=(list<T> lt){swap(lt); return *this;}void clear(){ iterator it = begin();while (it != end()){it = erase(it);}}void push_back(const T& x){insert(end(), x);}void push_front(const T& x){insert(begin(), x);}void pop_back(){erase(--end());}void pop_front(){erase(begin()); }iterator insert(iterator pos, const T& x){Node* cur = pos._node;Node* prev = cur->_prev;Node* newnode = new Node(x);prev->_next = newnode;newnode->_next = cur;cur->_prev = newnode;newnode->_prev = prev; return newnode;}iterator erase(iterator pos){assert(pos != end());Node* cur = pos._node;Node* prev = cur->_prev;Node* next = cur->_next;prev->_next = next;next->_prev = prev;delete cur;return next;}private:Node* _head;};}

结尾: 

到这里,我们的list也就告一段落了。大部分知识再看一次是不够的,很多都可以要自己画图对其进行理解,并且list的一些知识到后面学习的时候还大有用处,它也是我们C++一个重要的板块,最后希望这篇博客能为学习的各位提供帮助。 

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

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

相关文章

通过融合UGV的地图信息和IMU的惯性测量数据,实现对车辆精确位置和运动状态的估计和跟踪研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

六、互联网技术——数据存储

文章目录 一、存储系统层次结构二、按照重要性分类三、磁盘阵列RAID三、RAID基础四、磁盘阵列分级五、数据备份与恢复六、容灾与灾难恢复 一、存储系统层次结构 常见的三层存储体系结构如下图所示&#xff0c;分为高速缓冲存储器、主存储器和外存储器。 二、按照重要性分类 …

VBA技术资料MF66:使用代码插入行或列

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。我的教程一共九套&#xff0c;分为初级、中级、高级三大部分。是对VBA的系统讲解&#xff0c;从简单的入门&#xff0c;到…

十二、同步互斥与通信

1、概述 (1)可以把多任务系统当做一个团队&#xff0c;里面的每一个任务就相当于团队中的一个人。团队成员之间要协调工作进度(同步)、争用会议室(互斥)、沟通(通信)。多任务系统中所涉及的概念&#xff0c;都可以在现实生活中找到例子。 (2)各类RTOS都会涉及这些概念&#x…

小程序入门笔记(一) 黑马程序员前端微信小程序开发教程

微信小程序基本介绍 小程序和普通网页有以下几点区别&#xff1a; 运行环境&#xff1a;小程序可以在手机的操作系统上直接运行&#xff0c;如微信、支付宝等&#xff1b;而普通网页需要在浏览器中打开才能运行。 开发技术&#xff1a;小程序采用前端技术进行开发&#xff0c;…

XC5013 马达驱动和充电集成一体的控制芯片 一档输出芯片

XC5013 是一款应用于马达驱动或 LED 驱动的控制芯片&#xff0c;集成了锂电池充电管理系统&#xff0c;设定一档高电平输 出&#xff0c;并带有对不同状态的 LED 指示功能。 XC5013 集成了涓流充电、恒流充电和恒压充电全过程的充电方式&#xff0c;浮充电压精度在全温度范…

正点原子嵌入式linux驱动开发——TF-A初探

上一篇笔记中&#xff0c;正点原子的文档简单讲解了一下什么是TF-A&#xff0c;并且也学习了如何编译TF-A。但是TF-A是如何运行的&#xff0c;它的一个运行流程并未涉及。TF-A的详细运行过程是很复杂的&#xff0c;涉及到很多ARM处理器底层知识&#xff0c;所以这一篇笔记的内容…

大促节奏:速卖通黑五接力双十一,如何打造产品权重瓜分活动流量

双十一和黑五作为一种独特的消费文化现象&#xff0c;已经逐渐成为了消费领域中的一块“金字招牌”。无论是消费者还是商家&#xff0c;都非常期待这一天的到来&#xff0c;因为它不仅代表着购物的欲望和刺激&#xff0c;更重要的是&#xff0c;双十一和黑五已经成为了一种全新…

全排列[中等]

优质博文&#xff1a;IT-BLOG-CN 一、题目 给定一个不含重复数字的数组nums&#xff0c;返回其所有可能的全排列。你可以按任意顺序返回答案。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,3] 输出&#xff1a;[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]] 示例…

不做静态化,当部署到服务器上的项目刷新出现404【已解决】

当线上项目刷新出现404页面解决方法&#xff1a; 在nginx配置里加入这样一段代码 try_files $uri $uri/ /index.html; 它的作用是尝试按照给定的顺序访问文件 变量解释 try_files 固定语法 $uri 指代home文件(ip地址后面的路径&#xff0c;假如是127.0.0.1/index/a.png&…

二项分布以及实现

文章目录 前言所谓二项分布就是只会产生两种结果的概率 1.概念 前言 所谓二项分布就是只会产生两种结果的概率 1.概念 下面是一个二项分布的的theano实现 import numpy as np import theano import theano.tensor as T from theano.tensor.nnet import conv from theano.ten…

只需5秒视频就能生成3D模型的AI工具——Luma AI

HI&#xff0c;同学们&#xff0c;我是赤辰&#xff0c;本期是第13篇AI工具类教程&#xff0c;文章底部准备了粉丝福利&#xff0c;看完后可领取&#xff01; 今天给大家介绍一款用视频生成3D模型内容的AI工具——Luma AI&#xff0c;基于神经渲染技术&#xff0c;只需拍摄照片…

计算机竞赛 题目:基于FP-Growth的新闻挖掘算法系统的设计与实现

文章目录 0 前言1 项目背景2 算法架构3 FP-Growth算法原理3.1 FP树3.2 算法过程3.3 算法实现3.3.1 构建FP树 3.4 从FP树中挖掘频繁项集 4 系统设计展示5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于FP-Growth的新闻挖掘算法系统的设计与实现…

Linux:TCP三握四挥简析

文章目录 1. 前言2. 背景3. TCP连接的建立和断开3.1 TCP协议状态机3.2 TCP的三握四挥3.2.1 TCP 连接建立的三次握手过程分析3.2.1.1 服务端和客户端套接字的创建3.2.1.2 服务端进入 LISTEN 状态3.2.1.3 服务端在 LISTEN 状态等待客户端的 SYN 请求3.2.1.4 客户端向服务端发送 S…

IIC控制器(2):PS端

书接上文&#xff1a; I2C控制器练习&#xff08;1&#xff09;_NoNoUnknow的博客-CSDN博客 SPI协议与FPGA的自动升级和多启动-CSDN博客 本文主要做一些基本知识的补充和工程参考。 写IIC需要注意的事情&#xff1a; 1.查询芯片手册获得slave地址&#xff0c;以及寄存器地址…

GhostNet原理解析及pytorch实现

论文&#xff1a;https://arxiv.org/abs/1911.11907 源码&#xff1a;https://github.com/huawei-noah/ghostnet 简要论述GhostNet的核心内容。 Ghost Net 1、Introduction 在训练良好的深度神经网络的特征图中&#xff0c;丰富甚至冗余的信息通常保证了对输入数据的全面理…

【数据结构】红黑树(C++实现)

​ ​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;数据结构 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 上一篇博客&#xff1a;【数据…

妙不可言的Python之旅----(二)

Python基础语法 什么是字面量 字面量&#xff1a;在代码中&#xff0c;被写下来的的固定的值&#xff0c;称之为字面量 常用的值类型 类型 描述 说明 数字&#xff08;Number&#xff09; 支持 • 整数&#xff08;int&#xff09; • 浮点数&#xff08;float&#xff…

手边酒店V2独立版小程序 1.0.21 免授权+小程序前端

手边酒店小程序独立版酒店宾馆订房系统支持创建多个小程序&#xff0c;让每一个客户单独管理属于自己的小程序。后台支持一键入住&#xff0c;一键退款、退押金、钟点房支持微信支付、模板消息。客服实时收到新的订单信息&#xff0c;可以在手机端处理订单。支持按日期维护房价…

在PHP8中使用instanceof操作符检测对象类型-PHP8知识详解

在PHP8中使用instanceof操作符可以检测当前对象属于哪个类。语法格式如下&#xff1a; objectName instanceof classname下面我们用一个实例来讲解使用instanceof操作符检测对象类型。 本实例将将创建3个类&#xff0c;其中有两个类是父类和子类的关系&#xff0c;然后实例化…