C++:模拟实现list及迭代器类模板优化方法
文章目录
- 迭代器
- 模拟实现
本篇模拟实现简单的list和一些其他注意的点
迭代器
如下所示是利用拷贝构造将一个链表中的数据挪动到另外一个链表中,构造两个相同的链表
list(const list<T>& lt)
{emptyinit();for (auto e : lt){push_back(e);}
}void test_list1()
{list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);lt.push_back(5);list<int> l2(lt);
}
lt作为形参,传引用可以提高传参的效率,同时应该加上const修饰来保证不会因为不小心修改了形参导致外部的实参也被修改,这样的结果是不应该的,因此就要加const把这个形参变成一个const对象
而问题又来了,const对象要使用的是const迭代器,而前面没有写const迭代器,因此这里就引入了const迭代器的实现
从vector的模拟实现中,看似似乎只需要在原来的迭代器的基础上加上一个const即可,但事实上:
const
迭代器和普通迭代器是两种不同的迭代器,不能直接在普通的迭代器后面加const
,原因?
要解决这个问题,先重新回顾一下vector中const迭代器的定义流程:
对比vector的迭代器,vector中的迭代器const版本和非const版本直接在非const版本后面加const使它变成const迭代器即可,这样在调用的时候就可以直接进行调用
对iterator
的定义,const版本就是在指针前面加上const,这样返回的就是const修饰的指针,因此就可以做到通过该迭代器只读,不可修改的作用
这里的迭代器本质上就是指针在底层进行访问,然后我们定义一个const指针,使得const指针就不能对指针指向的内容进行修改了
下面仿照vector修改的原理修改list
要修改的部分其实就是下面的代码:
iterator begin()
{return iterator(_head->_next);
}iterator end()
{return iterator(_head);
}
在函数后加const很简单,但是核心是要把返回值也定义为const指针版本,这个过程要如何实现?
由于这里是把iterator封装成了一个类进行的实现,因此需要重新封装一个类进行实现
template <class T>struct __list_iterator{typedef list_node<T> Node;typedef __list_iterator<T> self;// 成员Node* _node;__list_iterator(Node* node):_node(node){}self& operator++(){_node = _node->_next;return *this;}self& operator--(){_node = _node->_prev;return *this;}self operator++(int){self tmp(*this);_node = _node->_next;return tmp;}self operator--(int){self tmp(*this);_node = _node->_prev;return tmp;}T& operator*(){return _node->_data;}T* operator->(){return &_node->_data;}bool operator==(const self& pos){return _node == pos._node;}bool operator!=(const self& pos){return !(*this == pos);}};template <class T>struct __list_const_iterator{typedef list_node<T> Node;typedef __list_const_iterator<T> self;// 成员Node* _node;__list_const_iterator(Node* node):_node(node){}self& operator++(){_node = _node->_next;return *this;}self& operator--(){_node = _node->_prev;return *this;}self operator++(int){self tmp(*this);_node = _node->_next;return tmp;}self operator--(int){self tmp(*this);_node = _node->_prev;return tmp;}const T& operator*(){return _node->_data;}const T* operator->(){return &_node->_data;}bool operator==(const self& pos){return _node == pos._node;}bool operator!=(const self& pos){return !(*this == pos);}};
但事实上,这两份代码只有很少的地方有区别,更多的内容都是相同的,这样是不满足较好的代码风格,因此在stl源码中,使用了模板对这两个类进行了封装
改进版本如下:
template <class T, class Ref, class Ptr >struct __list_iterator{typedef list_node<T> Node;typedef __list_iterator<T, Ref, Ptr> self;// 成员Node* _node;__list_iterator(Node* node):_node(node){}self& operator++(){_node = _node->_next;return *this;}self& operator--(){_node = _node->_prev;return *this;}self operator++(int){self tmp(*this);_node = _node->_next;return tmp;}self operator--(int){self tmp(*this);_node = _node->_prev;return tmp;}Ref operator*(){return _node->_data;}Ptr operator->(){return &_node->_data;}bool operator==(const self& pos){return _node == pos._node;}bool operator!=(const self& pos){return !(*this == pos);}};template <class T>class list{void emptyinit(){_head = new Node();_head->_next = _head;_head->_prev = _head;_size = 0;}public:typedef list_node<T> Node;typedef __list_iterator<T, T&, T*> iterator;typedef __list_iterator<T, const T&, const T*> const_iterator;// 构造函数 list(){emptyinit();}// 拷贝构造list(const list<T>& lt){emptyinit();auto it = lt.begin();//*it = 30;}void push_back(const T& x){insert(end(), x);}void push_front(const T& x){insert(begin(), x);}// head tail->prev tailvoid pop_back(){erase(--end());}void pop_front(){erase(begin());}iterator begin(){return iterator(_head->_next);}iterator end(){return iterator(_head);}const_iterator begin() const{return const_iterator(_head->_next);}const_iterator end() const{return const_iterator(_head);}iterator insert(iterator pos, const T& x){Node* cur = pos._node;Node* prev = cur->_prev;Node* newnode = new Node(x);// newnode// prev curprev->_next = newnode;newnode->_prev = prev;newnode->_next = cur;cur->_prev = newnode;return iterator(newnode);}iterator erase(iterator pos){Node* cur = pos._node;Node* prev = cur->_prev;Node* next = cur->_next;// prev cur nextprev->_next = cur->_next;next->_prev = cur->_prev;return iterator(next);}private:Node* _head;size_t _size;};
这里引入了类模板的概念,简单来说,当需要调用const类型时就会模板实例化出一个const版本的迭代器,再进行相关的操作,这样的操作可以避免代码冗余,也是模板的强大之处
模拟实现
#pragma once// 实现的是双向循环链表,链表中应该包含节点类和迭代器类,节点类用于从内存中申请节点,迭代器类用于获取节点指针
namespace mylist
{// 把节点进行封装,可以动态获取一个节点template <class T>struct list_node{// 成员list_node<T>* _next;list_node<T>* _prev;T _data;// 成员函数list_node(const T& val = T()):_data(val), _next(nullptr), _prev(nullptr){}};// 对迭代器进行封装,使得外界看到的是迭代器// 迭代器当中存储的是某个节点的指针// 可以对迭代器进行各项操作template <class T, class Ref, class Ptr >struct __list_iterator{typedef list_node<T> Node;typedef __list_iterator<T, Ref, Ptr> self;// 成员Node* _node;__list_iterator(Node* node):_node(node){}self& operator++(){_node = _node->_next;return *this;}self& operator--(){_node = _node->_prev;return *this;}self operator++(int){self tmp(*this);_node = _node->_next;return tmp;}self operator--(int){self tmp(*this);_node = _node->_prev;return tmp;}Ref operator*(){return _node->_data;}Ptr operator->(){return &_node->_data;}bool operator==(const self& pos){return _node == pos._node;}bool operator!=(const self& pos){return !(*this == pos);}};// 适配器 -- 复用template <class T, class Ref, class Ptr >struct __reverse_iterator{typedef list_node<T> Node;typedef __reverse_iterator<T, Ref, Ptr> self;// 成员Node* _node;__reverse_iterator(Node* node):_node(node){}self& operator++(){_node = _node->_prev;return *this;}self& operator--(){_node = _node->_next;return *this;}self operator++(int){self tmp(*this);_node = _node->_prev;return tmp;}self operator--(int){self tmp(*this);_node = _node->_next;return tmp;}Ref operator*(){return _node->_data;}Ptr operator->(){return &_node->_data;}bool operator==(const self& pos){return _node == pos._node;}bool operator!=(const self& pos){return !(*this == pos);}};template <class T>class list{void emptyinit(){_head = new Node();_head->_next = _head;_head->_prev = _head;_size = 0;}public:typedef list_node<T> Node;typedef __list_iterator<T, T&, T*> iterator;typedef __list_iterator<T, const T&, const T*> const_iterator;typedef __reverse_iterator<T, T&, T*> reverse_iterator;typedef __reverse_iterator<T, const T&, const T*> const_reverse_iterator;// 构造函数 list(){emptyinit();}// 拷贝构造list(const list<T>& lt){emptyinit();auto it = lt.begin();//*it = 30;}void push_back(const T& x){insert(end(), x);}void push_front(const T& x){insert(begin(), x);}// head tail->prev tailvoid pop_back(){erase(--end());}void pop_front(){erase(begin());}iterator begin(){return iterator(_head->_next);}iterator end(){return iterator(_head);}const_iterator begin() const{return const_iterator(_head->_next);}const_iterator end() const{return const_iterator(_head);}reverse_iterator rbegin(){return reverse_iterator(_head->_prev);}reverse_iterator rend(){return reverse_iterator(_head);}const_reverse_iterator rbegin() const{return const_reverse_iterator(_head->_prev);}const_reverse_iterator rend() const{return const_reverse_iterator(_head);}iterator insert(iterator pos, const T& x){Node* cur = pos._node;Node* prev = cur->_prev;Node* newnode = new Node(x);// newnode// prev curprev->_next = newnode;newnode->_prev = prev;newnode->_next = cur;cur->_prev = newnode;return iterator(newnode);}iterator erase(iterator pos){Node* cur = pos._node;Node* prev = cur->_prev;Node* next = cur->_next;// prev cur nextprev->_next = cur->_next;next->_prev = cur->_prev;return iterator(next);}private:Node* _head;size_t _size;};void test_list1(){list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);lt.push_back(5);cout << "正序" << endl;for (auto e : lt){cout << e << " ";}cout << endl;cout << "逆序" << endl;auto rit = lt.rbegin();while (rit != lt.rend()){cout << *rit << " ";rit++;}cout << endl;}
}
相关文章:

C++:模拟实现list及迭代器类模板优化方法
文章目录 迭代器模拟实现 本篇模拟实现简单的list和一些其他注意的点 迭代器 如下所示是利用拷贝构造将一个链表中的数据挪动到另外一个链表中,构造两个相同的链表 list(const list<T>& lt) {emptyinit();for (auto e : lt){push_back(e);} }void test_…...
k8s整合istio配置gateway入口、配置集群内部服务调用管理
一、 istio gateway使用demo kubectl apply -f - <<EOF apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata:name: ngdemo-gatewaynamespace: ssx spec:selector:istio: ingressgateway # use Istio default gateway implementationservers:- port:numbe…...

工程监测振弦采集仪采集到的数据如何进行分析和处理
工程监测振弦采集仪采集到的数据如何进行分析和处理 振弦采集仪是一个用于测量和记录物体振动的设备。它通过测量物体表面的振动来提取振动信号数据,然后将其转换为数字信号,以便进行分析和处理。在实际应用中,振弦采集仪是广泛应用于机械、建…...

(三)行为模式:2、命令模式(Command Pattern)(C++示例)
目录 1、命令模式(Command Pattern)含义 2、命令模式的UML图学习 3、命令模式的应用场景 4、命令模式的优缺点 5、C实现命令模式的实例 1、命令模式(Command Pattern)含义 命令模式(Command)ÿ…...

微信小程序 蓝牙设备连接,控制开关灯
1.前言 微信小程序中连接蓝牙设备,信息写入流程 1、检测当前使用设备(如自己的手机)是否支持蓝牙/蓝牙开启状态 wx:openBluetoothAdapter({}) 2、如蓝牙已开启状态,检查蓝牙适配器的状态 wx.getBluetoothAdapterState({}) 3、添加…...

Python 矢量数据库和矢量索引:构建 LLM 应用程序
推荐:使用 NSDT场景编辑器 助你快速搭建可二次编辑的3D应用场景 由于使用其硬件创建的生成式AI应用程序,Nvidia经历了显着的增长。另一项软件创新,矢量数据库,也正在乘着生成式人工智能的浪潮。 开发人员正在向量数据库上用Pytho…...

-Webkit-Box 在 Safari 中出现的兼容性问题
一、问题背景: UI要求要实现这样的效果,使用 display:-webket-box在chrome浏览器下完美解决 但是马上啪啪打脸,在safari浏览器下显示空白 ,不能不说浏览器之间的兼容性简直就是天坑 二、解决办法 通过浏览器调试发现原本float的…...

后端项目打包上传服务器记录
后端项目打包上传服务器记录 文章目录 后端项目打包上传服务器记录1、项目打包2、jar包上传服务器 本文记录打包一个后端项目,上传公司服务器的过程。 1、项目打包 通过IDEA的插件进行打包: 打成一个jar包,jar包的位置在控制台可以看到。 2、…...

ubuntu部署haproxy
HAProxy是可提供高可用性、负载均衡以及基于TCP和HTTP应用的代理. 1、更新系统报 通过在终端中运行以下命令,确保所有系统包都是最新的 sudo apt updatesudo apt upgrade2、安装Haproxy sudo apt install haproxy设置开机自动启动haproxy服务 sudo systemctl en…...

vue利用 sortable 完成表格拖拽
先讲一下vue2,使用sortable完成表格拖拽【不只是表格,div也可以实现,但我项目中是表格拖拽】 github地址 安装 npm install sortablejs --save使用 (我的项目中是拖拽一个小按钮移动,而不是整行) <te…...

CNN简介3
...

新能源电动车充电桩控制主板安全特点
新能源电动车充电桩控制主板安全特点 你是否曾经担心过充电桩的安全问题?充电桩主板又是什么样的呢?今天我们就来聊聊这个话题。 充电桩主板采用双重安全防护系统,包括防水、防护、防尘等,确保充电桩安全、可靠。不仅如此,充电桩主板采用先…...

公路桥梁有哪些安全隐患?
在现代社会,公路桥梁作为连接城市、串联交通的重要纽带,扮演着无可替代的角色。然而,我们常常忽视的是,这些高架构筑物也存在着潜在的安全隐患,可能随时影响着交通的畅通和人们的生命财产安全。为了更好地认识和理解这…...

【C语言】每日一题(错误的集合)
最近在牛客、力扣上做题,花费海量时间,苦不堪言,有时绞尽脑汁也想不出,痛定思痛,每日记录写的比较困难的题。 错误的集合 题目如上图所示 题主乍看之下觉得很简单,再看例子,不就是一个有序数组…...

[JavaWeb]【四】web后端开发-SpringBootWeb入门
目录 一 Spring 二 SpringBootWeb入门 2.1 入门需求 2.2 分析 2.3 开始创建SpringBootWeb 2.4 创建类实现需求 2.5 启动程序 2.6 访问 三 HTTP协议 3.1 HTTP-概述 3.2 HTTP-请求协议 3.3 HTTP-响应协议 3.3.1 响应状态码 && 响应类型 3.4 HTTP-协议解析 前言…...
前端css
day03-CSS基础 目标:掌握 CSS 属性基本写法,能够使用文字相关属性美化文章页。 01-CSS初体验 层叠样式表 (Cascading Style Sheets,缩写为 CSS),是一种 样式表 语言,用来描述 HTML 文档的呈现(…...
vb+sql医院门诊管理系统设计与系统
摘要 信息时代已经来临,计算机应用于医院的日常管理,为医院的现代化带来了从未有过的动力和机遇,为医疗卫生领域的发展提供了无限的潜力。采用计算机管理信息系统已成为医院管理科学化和现代化的标志,给医院带来了明显的经济效益和社会效益。 本文介绍了数据库管理系统的…...

bootstrap-modal调用ajax后不经过回调函数
说明:我用的是boostrap的弹框,表单用的是layui的,个人觉得bootstrap比layui的弹框好看点,能自适应高度。 如图:点击保存后里面的内容不执行 原因:type用的是submit 解决:把submit改为button...

【【典型电路设计之片内存储器的设计之RAM的Verilog HDL描述一】】
典型电路设计之片内存储器的设计之RAM的Verilog HDL描述一 RAM是随机存储器,存储单元的内容可按需随意取出或存入。这种存储器在断电后将丢失所有数据,一般用来存储一些短时间内使用的程序和数据。 其内部结构如下图所示: 例:用…...

食品行业案例 | 燕千云助力头部食品企业搭建数智化 IT服务管理体系及平台
随着数字化时代的到来,食品行业呈现出多个发展趋势。首先,消费者对健康食品和功能性食品的关注度提高,推动了市场需求的增长。其次,便利食品和物流行业迅速发展,满足了快节奏生活的需求。再者,电商渠道和网…...

网络编程(Modbus进阶)
思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...
基于算法竞赛的c++编程(28)结构体的进阶应用
结构体的嵌套与复杂数据组织 在C中,结构体可以嵌套使用,形成更复杂的数据结构。例如,可以通过嵌套结构体描述多层级数据关系: struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...
线程同步:确保多线程程序的安全与高效!
全文目录: 开篇语前序前言第一部分:线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分:synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分ÿ…...

C/C++ 中附加包含目录、附加库目录与附加依赖项详解
在 C/C 编程的编译和链接过程中,附加包含目录、附加库目录和附加依赖项是三个至关重要的设置,它们相互配合,确保程序能够正确引用外部资源并顺利构建。虽然在学习过程中,这些概念容易让人混淆,但深入理解它们的作用和联…...

边缘计算网关提升水产养殖尾水处理的远程运维效率
一、项目背景 随着水产养殖行业的快速发展,养殖尾水的处理成为了一个亟待解决的环保问题。传统的尾水处理方式不仅效率低下,而且难以实现精准监控和管理。为了提升尾水处理的效果和效率,同时降低人力成本,某大型水产养殖企业决定…...

基于stm32F10x 系列微控制器的智能电子琴(附完整项目源码、详细接线及讲解视频)
注:文章末尾网盘链接中自取成品使用演示视频、项目源码、项目文档 所用硬件:STM32F103C8T6、无源蜂鸣器、44矩阵键盘、flash存储模块、OLED显示屏、RGB三色灯、面包板、杜邦线、usb转ttl串口 stm32f103c8t6 面包板 …...
Qt Quick Controls模块功能及架构
Qt Quick Controls是Qt Quick的一个附加模块,提供了一套用于构建完整用户界面的UI控件。在Qt 6.0中,这个模块经历了重大重构和改进。 一、主要功能和特点 1. 架构重构 完全重写了底层架构,与Qt Quick更紧密集成 移除了对Qt Widgets的依赖&…...

汇编语言学习(三)——DoxBox中debug的使用
目录 一、安装DoxBox,并下载汇编工具(MASM文件) 二、debug是什么 三、debug中的命令 一、安装DoxBox,并下载汇编工具(MASM文件) 链接: https://pan.baidu.com/s/1IbyJj-JIkl_oMOJmkKiaGQ?pw…...

mq安装新版-3.13.7的安装
一、下载包,上传到服务器 https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.13.7/rabbitmq-server-generic-unix-3.13.7.tar.xz 二、 erlang直接安装 rpm -ivh erlang-26.2.4-1.el8.x86_64.rpm不需要配置环境变量,直接就安装了。 erl…...

C#学习12——预处理
一、预处理指令: 解释:是在编译前由预处理器执行的命令,用于控制编译过程。这些命令以 # 开头,每行只能有一个预处理指令,且不能包含在方法或类中。 个人理解:就是游戏里面的备战阶段(不同对局…...