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;}
}

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

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

相关文章

运动路径规划,ROS发布期望运动轨迹

目录 一、Python实现&#xff08;推荐方法&#xff09; 1.1代码cubic_spline_path.py 1.2使用方法 二、C实现 参考博客 想让机器人/智能车无人驾驶&#xff0c;要有期望路径&#xff0c;最简单的是一条直线&#xff0c;或者是一条光滑曲线。 生成路径的方法有两种&#xf…

【网络编程(二)】NIO快速入门

NIO Java NIO 三大核心组件 Buffer&#xff08;缓冲区&#xff09;&#xff1a;每个客户端连接都会对应一个Buffer&#xff0c;读写数据通过缓冲区读写。Channel&#xff08;通道&#xff09;&#xff1a;每个channel用于连接Buffer和Selector&#xff0c;通道可以进行双向读…

Redis数据库的可视化工具AnotherRedisDesktopManager使用+抖音直播小玩法实践

一、它是什么 Another Redis DeskTop Manager 是一个开源项目&#xff0c;提供了以可视化的方式管理 Redis 的功能&#xff0c;可供免费下载安装&#xff0c;也可以在此基础上进行二次开发&#xff0c;主要特点有&#xff1a; 支持 Windows 平台和 MacOS 平台 支持查询 Key、…

QT中的按钮控件Buttons介绍

目录 Buttons 按钮控件 1、常用属性介绍 2、按钮介绍 2.1QPushButton 普通按钮 2.2QtoolButton 工具按钮 2.3Radio Button单选按钮 2.4CheckButton复选按钮 2.5Commam Link Button命令链接按钮 2.6Dialog Button Box命令链接按钮 Buttons 按钮控件 在Qt里&#xff0c;…

Viobot开机指南

0.前言 本篇旨在让每个拿到Viobot设备的用户都能够第一时间测试它的效果&#xff0c;以及将设备配置到自己的环境下面。 1.上电 首先&#xff0c;我们先要把设备接上电源线和网线&#xff0c;最简单的方式就是网线直连电脑。 电源选用12V1.5A设备自带的电源即可。 2.配置网…

深入学习前端开发,掌握HTML、CSS、JavaScript等技术

课程链接&#xff1a; 链接: https://pan.baidu.com/s/1WECwJ4T8UQfs2FyjUMbxig?pwdi654 提取码: i654 复制这段内容后打开百度网盘手机App&#xff0c;操作更方便哦 --来自百度网盘超级会员v4的分享 课程介绍&#xff1a; 第1周&#xff1a;HTML5基础语法与标签 &#x1f…

web集群学习:搭建 LNMP应用环境

目录 LNMP的介绍&#xff1a; LNMP组合工作流程&#xff1a; FastCGI介绍&#xff1a; 1、什么是 CGI 2、什么是 FastCGI 配置LNMP 1、部署LNMP环境 2、配置LNMP环境 LNMP的介绍&#xff1a; 随着 Nginx Web 服务的逐渐流行&#xff0c;又岀现了新的 Web 服务环境组合—…

【Spring Cloud 八】Spring Cloud Gateway网关

gateway网关 系列博客背景一、什么是Spring Cloud Gateway二、为什么要使用Spring Cloud Gateway三、 Spring Cloud Gateway 三大核心概念4.1 Route&#xff08;路由&#xff09;4.2 Predicate&#xff08;断言&#xff09;4.3 Filter&#xff08;过滤&#xff09; 五、Spring …

如何使用Kali Linux进行密码破解?

今天我们探讨Kali Linux的应用&#xff0c;重点是如何使用它来进行密码破解。密码破解是渗透测试中常见的任务&#xff0c;Kali Linux为我们提供了强大的工具来帮助完成这项任务。 1. 密码破解简介 密码破解是一种渗透测试活动&#xff0c;旨在通过不同的方法和工具来破解密码…

力扣初级算法(数组拆分)

力扣初级算法&#xff08;数组拆分&#xff09; 每日一算法&#xff1a; 力扣初级算法&#xff08;数组拆分&#xff09; 学习内容&#xff1a; 1.问题描述 给定长度为 2n 的整数数组 nums &#xff0c;你的任务是将这些数分成 n 对, 例如 (a1, b1), (a2, b2), …, (an, bn) …

机器人CPP编程基础-03变量类型Variables Types

机器人CPP编程基础-02变量Variables 全文AI生成。 C #include<iostream>using namespace std;main() {int a10,b35; // 4 bytescout<<"Value of a : "<<a<<" Address of a : "<<&a <<endl;cout<<"Val…

Vue+ElementUI实现选择指定行导出Excel

这里记录一下&#xff0c;今天写项目时 的一个需求&#xff0c;就是通过复选框选中指定行然后导出表格中选中行的Excel表格 然后这里介绍一个工具箱(模板)&#xff1a;vue-element-admin 将它拉取后&#xff0c;运行就可以看到如下界面&#xff1a; 这里面的很多功能都已经实现…

【NAS群晖drive异地访问】使用cpolar远程访问内网Synology Drive「内网穿透」

文章目录 前言1.群晖Synology Drive套件的安装1.1 安装Synology Drive套件1.2 设置Synology Drive套件1.3 局域网内电脑测试和使用 2.使用cpolar远程访问内网Synology Drive2.1 Cpolar云端设置2.2 Cpolar本地设置2.3 测试和使用 3. 结语 前言 群晖作为专业的数据存储中心&…

jupyter切换conda虚拟环境

环境安装 conda install nb_conda 进入你想使用的虚拟环境&#xff1a; conda activate your_env_name 在你想使用的conda虚拟环境中&#xff1a; conda install -y jupyter 在虚拟环境中安装jupyter&#xff1a; conda install -y jupyter 重启jupyter 此时我们已经把该安装…

也许你正处于《孤注一掷》中的“团队”,要留心了

看完这部电影&#xff0c;心情久久不能平静&#xff0c;想了很多&#xff0c;倒不是担心自己哪天也成为“消失的yaozi”&#xff0c;而是在想&#xff0c;我们每天所赖以生存的工作&#xff0c;跟电影里他们的工作比&#xff0c;差别在哪里呢&#xff1f; 目录 1. 产品的本质…

【QT+ffmpeg】QT+ffmpeg 环境搭建

1.qt下载地址 download.qt.io/archive/ 2. win10sdk 下载 https://developer.microsoft.com/en-us/windows/downloads/windows-sdk/ 安装 debug工具路径 qtcreater会自动识别 调试器选择

74、75、76——tomcat项目实战

tomcat项目实战 tomcat 依赖 java运行环境,必须要有jre , 选择 jdk1.8 JvmPertest 千万不能用 kyj易捷支付 项目机器 选择 一台机器 ,安装jdk1.8的机器下载tomcat的包 上传到机器,解压tomcattomcat文件 bin文件夹: 启动文件 堆栈配置文件 catalina.sh JAVA_OPTS="-Xm…

gitlab合并新项目和分支切换

一、新建项目 1、创建空白项目 2、先创建一个群组 3、编写群组信息 4、创建群组完成以后新建项目 ​​​​​​​ 二、将代码推送到gitlab 1、初始化 git init 2、关联gitlab地址 # 比如:http://192.168.139.128:7070/cloud/obwt_cloud.git git remote add origin <你…

FreeRTOS qemu mps2-an385 bsp 移植制作 :串口打印篇

相关文章 FreeRTOS qemu mps2-an385 bsp 移植制作 &#xff1a;环境搭建篇 FreeRTOS qemu mps2-an385 bsp 移植制作 &#xff1a;系统启动篇 FreeRTOS qemu mps2-an385 bsp 移植制作 &#xff1a;系统运行篇 开发环境 Win10 64位 VS Code&#xff0c;ssh 远程连接 ubuntu …

如何使用Python编写小游戏?

大家好&#xff0c;我是沐尘而生&#xff0c;如果你是一个热爱编程的小伙伴&#xff0c;又想尝试游戏开发&#xff0c;那么这篇文章一定能满足你的好奇心。不废话&#xff0c;让我们马上进入Python游戏开发的精彩世界吧&#xff01; Python游戏开发的魅力 编写小游戏不仅仅是锻…