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++一个重要的板块,最后希望这篇博客能为学习的各位提供帮助。
相关文章:
C++——list(2)
作者:几冬雪来 时间:2023年9月28日 内容:C——list内容讲解 目录 前言: list的const迭代器: const的iterator: const迭代器: operator->: 拷贝构造: 迭代器接口补充&…...
Django基础讲解-路由控制器和视图(Django-02)
一 路由控制器 参考链接: Django源码阅读:路由(二) - 知乎 Route路由, 是一种映射关系!路由是把客户端请求的 url路径与视图进行绑定 映射的一种关系。 这个/timer通过路由控制器最终匹配到myapp.views中的视图函数 …...
【算法题】2873. 有序三元组中的最大值 I
题目: 给你一个下标从 0 开始的整数数组 nums 。 请你从所有满足 i < j < k 的下标三元组 (i, j, k) 中,找出并返回下标三元组的最大值。如果所有满足条件的三元组的值都是负数,则返回 0 。 下标三元组 (i, j, k) 的值等于 (nums[i]…...
HTML5 跨屏前端框架 Amaze UI
Amaze UI采用国际最前沿的“组件式开发”以及“移动优先”的设计理念,基于其丰富的组件,开发者可通过简单拼装即可快速构建出HTML5网页应用,上线仅半年,Amaze UI就成为了国内最流行的前端框架,目前在Github上收获Star数…...
EXCEL会计记账报表财务软件企业公司做账系统凭证自动生成报表
本系统基于VBA编程设计,具有界面简洁美观,操作方便快捷,功能完备实用的特点,系统分为基本信息、凭证处理、账簿查询、会计报表、固定资产管理、系统管理、凭证数据库七大模块,您只需要录入记账凭证,就可以自…...
Can‘t pickle <class ‘__main__.Test‘>: it‘s not the same object as __main__.Test
目录 原因1 类名重复了 案例1 变量名和类名重复 原因1 类名重复了 检查项目代码,是不是其他地方有同名类。 案例1 变量名和类名重复 转自:python3报错Cant pickle <class __main__.Test>: its not the same object as __main__.Test解决 - 知乎…...
第九章 动态规划 part14 1143. 最长公共子序列 1035. 不相交的线 53. 最大子序和
第五十六天| 第九章 动态规划 part14 1143. 最长公共子序列 1035. 不相交的线 53. 最大子序和 一、1143. 最长公共子序列 题目链接: 题目介绍: 思路: 本题和“最长重复子数组”区别在于**这里不要求是连续的了,但要有相对顺序*…...
腾讯云服务器南京地域详细介绍、测试IP和Ping值测速
腾讯云服务器南京地域怎么样?南京地域很不错,正好处于中间的位置,南方北方用户均可以选择,网络延迟更低速度更快,并且目前南京地域有活动,南京地域可用区可选南京一区、南京二区和南京三区,腾讯…...
理解CSS的层叠性和继承性
CSS的层叠性(cascading)指的是在同一元素上应用多个样式时,不同样式之间的优先级别以及如何进行组合和冲突解决的规则。具体来说,CSS采用的是“选择器优先级”规则来判断哪个样式优先级更高,如果多个样式的优先级相同&…...
OSI体系结构和TCP/IP体系结构
在第一章( 计网第一章 )的时候,曾经提到过OSI体系结构和TCP/IP体系结构,并对它们进行了简单的对比。这篇博客在其基础上进行更深层次的理解。 一.OSI体系结构: 通信子网: 计算机网络在逻辑功能上可以分为…...
侯捷 C++ STL标准库和泛型编程 —— 8 适配器
8 适配器 适配器 Adapter 只是一个小变化,比如改个接口,函数名称等等其出现在三个地方:仿函数适配器,迭代器适配器,容器适配器可以使用继承 / 复合的两种方式实现,STL中都用复合 其思想就是将该记的东西记…...
每日一题 416 分割等和子集(01背包)
题目 分割等和子集 给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。 示例 1: 输入:nums [1,5,11,5] 输出:true 解释:数组可以分割成 [1, 5, 5] …...
U盘插上就显示让格式化是坏了吗?
U盘以其体积小巧、存储容量大、读写速度快的特点,在各种工作和个人使用场合中得到了广泛应用,因此深得用户好评。然而,在日常使用U盘的过程中,经常会遇到一些问题和挑战。今天,我将为大家详细解释U盘出现要求格式化的现…...
分布式应用程序协调服务 ZooKeeper 详解
目录 1、ZooKeeper简介 2、ZooKeeper的使用场景 3、ZooKeeper设计目的 4、ZooKeeper数据模型 5、ZooKeeper几个重要概念 5.1、ZooKeeper Session 5.2、ZooKeeper Watch 5.3、Consistency Guarantees 6、ZooKeeper的工作原理 6.1、Leader Election 6.2、Leader工作流…...
Anniversary party(树形dp 基础题)
1.题目大意 There is going to be a party to celebrate the 80-th Anniversary of the Ural State University. The University has a hierarchical structure of employees. It means that the supervisor relation forms a tree rooted at the rector V. E. Tretyakov. In …...
Junit的常用操作
注:本篇文章讲解的是junit5 目录 Juint是什么 Juint需要导入的依赖 Juint常用注解 Junit执行顺序 参数化 断言 测试套件 Juint是什么 Juint 是 Java 的一个单元测试框架. 也是回归测试框架. 使用 Junit 能让我们快速的完成单元测试。 注意:Junit 测试也是程序…...
Elasticsearch安装并使用Postman访问
Elasticsearch,一个强大的开源搜索和分析引擎,已经在全球范围内被广泛应用于各种场景,包括网站搜索、日志分析、实时应用等。由于其强大的功能和灵活性,Elasticsearch 已经成为大数据处理的重要工具。然而,对于许多初次…...
Pytorch深度学习训练模型保存问题,找不到保存路径
执行torch.save(net.state_dict(), save_path_pth)报错: RuntimeError: Parent directory D:\xxxxxxxxxxx\weights does not exist. 将文件路径的中文改成全英文就可以了。 注意:这个代码在torch1.7版本无报错,但是在1.13.1版本报错。在linu…...
数据结构与算法之堆: Leetcode 23. 合并 K 个升序链表 (Typescript版)
合并 K 个升序链表 https://leetcode.cn/problems/merge-k-sorted-lists/ 描述 给你一个链表数组,每个链表都已经按升序排列请你将所有链表合并到一个升序链表中,返回合并后的链表 示例 1 输入:lists [[1,4,5],[1,3,4],[2,6]] 输出&…...
代码随想录算法训练营第五十七天 | 392.判断子序列 115.不同的子序列
1. 判断子序列 392. 判断子序列 - 力扣(LeetCode) dp[i][j] 表示以下标i-1为结尾的字符串s,和以下标j-1为结尾的字符串t,相同子序列的长度。 class Solution {public boolean isSubsequence(String s, String t) {//dp[i][j] 表示…...
Kafka日志索引详解以及生产常见问题分析与总结
文章目录 1、Kafka的Log日志梳理1.1、Topic下的消息是如何存储的?1.1.1、 log文件追加记录所有消息1.1.2、 index和timeindex加速读取log消息日志。 1.2、文件清理机制1.2.1、如何判断哪些日志文件过期了1.2.2、过期的日志文件如何处理 1.3、Kafka的文件高效读写机制…...
vue中 css scoped原理
Vue中css的逻辑是先放子组件,然后放父组件,所以同样的css类名,子组件会被父组件覆盖 html 如下 子被父覆盖 scoped是通过给组件加hash值,锁定组件。 父子组件均scoped的情况下,子仍会覆盖 还是被覆盖了 如何避免被…...
tf.compat.v1.global_variables()
tf.global_variables tf.global_variables() 是 TensorFlow 1.x 中的一个函数,它返回图中所有的全局变量。在 TensorFlow 2.x 中,这个函数已经被移除了,取而代之的是 tf.compat.v1.global_variables()。 然而,在 TensorFlow 2.x …...
登录注册实现
一、前端页面注册到Vue 1.创建登录和注册组件 <template><div>login</div></template><script> export default {name: HomeView,data() {return {}},methods: {}, } </script><template><div>register</div></tem…...
Push rejected: Push to origin/master was rejected
Push rejected: Push to origin/master was rejected 原因:推拒绝:推送到起源/主人被拒绝 解决方案如下: 方案1: 1.在Idea打开终端 方案2: 1、在对应项目文件里打开 Git Bash 然后依次输入: git pull …...
在线OJ项目核心思路
文章目录 在线OJ项目核心思路1. 项目介绍2.预备知识理解多进程编程为啥采用多进程而不使用多线程?标准输入&标准输出&标准错误 3.项目实现题目API实现相关实体类定义新增/修改题目获取题目列表 编译运行编译运行流程 4.统一功能处理 在线OJ项目核心思路 1. 项目介绍 …...
Spring MVC:数据绑定
Spring MVC 数据绑定数据类型转换数据格式化数据校验 附 数据绑定 数据绑定,指 Web 页面上请求和响应的数据与 Controller 中对应处理方法上的对象绑定(即是将用户提交的表单数据绑定到 Java 对象中)。 过程如下: ServletRequest…...
STM32CubeMX学习笔记-USB接口使用(HID按键)
STM32CubeMX学习笔记-USB接口使用(HID按键) 一、USB简介1.1 USB HID简介 二、新建工程1. 打开 STM32CubeMX 软件,点击“新建工程”2. 选择 MCU 和封装3. 配置时钟4. 配置调试模式 三、USB3.1 参数配置3.2 引脚配置3.3 配置时钟3.4 USB Device…...
C#,数值计算——Ranq2的计算方法与源程序
1 文本格式 using System; namespace Legalsoft.Truffer { /// <summary> /// Backup generator if Ranq1 has too short a period and Ran is too slow.The /// period is 8.5E37. Calling conventions same as Ran, above. /// </summary> …...
C/C++ 数据结构 - 链表
1.单链表 https://blog.csdn.net/qq_36806987/article/details/79858957 1 #include<stdio.h>2 #include<stdlib.h>3 4 /*结构体部分*/5 typedef struct Node6 {7 int data; //数值域8 struct Node *next; //指针域9 }N;10 11 N *Init() //初始化单…...
wordpress全屏滚轴/给公司做网站要多少钱
Miracles sometimes occur, but one has to work terribly hard for them. 奇迹有时候是会发生的,但是你得为之拼命地努力。(Chaim Weizmann, First president of Israel) 原文载于:爱词霸英语学习网-每日一句 Chaim Weizmann 人物简介: h…...
武昌网站建设价格多少钱/央视网新闻
前言:前面我们都是使用JTAG方式下载比特流文件,然后下载elf文件,最后点击Run as或者Debug as来运行程序。JTAG方式是通过tcl脚本来初始化PS,然后用JTAG收发信息,优点是可以在线调试,缺点是断电后程序就丢失…...
网站建设皖icp/产品推广策划方案怎么做
1. 通过 浏览器的控件使用$_FILE 和服务器后端进行交互上传 True: { "name": "HD.Club-4K-Chimei-inn-20mbps.mp4", "type": "video\/mp4", "tmp_name": "D:\\mySoft\\wamp64\\tmp\\phpDD30.tmp", …...
建设网站的3个必要条件/seo是什么软件
根据《网络世界》报道: 搜索巨人Google于7月21日发布了2006年第二财季财报,因为成功躲避了影响雅虎和易趣的行业增长减缓趋势,Google利润增长达到了110%。尽管Google的增长依然强劲,甚至高出华尔街分析师的预测,但这并…...
静态网站模板/百度快速排名提升
双缝实验Double-slit experiment 假若光束是由经典粒子组成,将光束照射于两条相互平行的狭缝,则在探射屏应该会观察到两个单缝图样的总和。但实际并不是这样,如下图所示,在探射屏显示出一系列明亮条纹与暗淡条纹相间的图样。 这个…...
手机网站有什么区别是什么意思/成都seo技术经理
巧用sessionStorage切换layui的操作按钮 最近用layui做了一个项目,其中有个模块就是切换layui的操作按钮,因为第一次用layui不大熟,慢慢调试终于搞出来,到达任意切换的效果。 【1】其他那些表格数据绑定就不写了,直接进…...