【C++STL】list的反向迭代器

news2024/11/15 17:15:10

list的反向迭代器

文章目录

        • list的反向迭代器
        • reverse.h
        • 疑问1:为什么在迭代器当中不需要写深拷贝、析构函数
        • 疑问2:为什么在迭代器当中需要三个模板参数?
        • 疑问3:反向迭代器是怎么实现的?
        • 疑问4:为什么*解引用不直接返回当前值
        • 为什么要加一些不认识的typedef

v2-87a8ee6be3ce86f87e9dcfc3a00df6da_r

reverse.h

#pragma once

namespace mudan
{
	template<class Iterator, class Ref, class Ptr>
	struct __reverse_iterator
	{
		Iterator _cur;
		typedef __reverse_iterator<Iterator, Ref, Ptr> RIterator;

		__reverse_iterator(Iterator it)
			:_cur(it)
		{}

		RIterator operator++()
		{
			--_cur;
			return *this;
		}

		RIterator operator--()
		{
			++_cur;
			return *this;
		}

		Ref operator*()
		{
			//return *_cur;
			auto tmp = _cur;
			--tmp;
			return *tmp;
		}

		Ptr operator->()
		{
			//return _cur.operator->();
			return &(operator*());
		}

		bool operator!=(const RIterator& it)
		{
			return _cur != it._cur;
		}
	};
}

list.h

#include<assert.h>
#include<iostream>
#include<algorithm>
#include"reverse.h"   
using namespace std;

namespace mudan
{

	template<class T>
	struct list_node
	{
		T _data;
		list_node<T>* _next;
		list_node<T>* _prev;

		list_node(const T& x = T())
			:_data(x)
			, _next(nullptr)
			, _prev(nullptr)
		{}
	};

	// typedef __list_iterator<T, T&, T*>             iterator;
	// typedef __list_iterator<T, const T&, const T*> const_iterator;

	// 像指针一样的对象
	template<class T, class Ref, class Ptr>
	struct __list_iterator
	{
		typedef list_node<T> Node;
		typedef __list_iterator<T, Ref, Ptr> iterator;

		typedef bidirectional_iterator_tag iterator_category;
		typedef T value_type;
		typedef Ptr pointer;
		typedef Ref reference;
		typedef ptrdiff_t difference_type;


		Node* _node;


		__list_iterator(Node* node)
			:_node(node)
		{}

		bool operator!=(const iterator& it) const
		{
			return _node != it._node;
		}

		bool operator==(const iterator& it) const
		{
			return _node == it._node;
		}

		// *it  it.operator*()
		// const T& operator*()
		// T& operator*()
		Ref operator*()
		{
			return _node->_data;
		}

		//T* operator->() 
		Ptr operator->()
		{
			return &(operator*());
		}

		// ++it
		iterator& operator++()
		{
			_node = _node->_next;
			return *this;
		}

		// it++
		iterator operator++(int)
		{
			iterator tmp(*this);
			_node = _node->_next;
			return tmp;
		}

		// --it
		iterator& operator--()
		{
			_node = _node->_prev;
			return *this;
		}

		// it--
		iterator operator--(int)
		{
			iterator tmp(*this);
			_node = _node->_prev;
			return tmp;
		}
	};

	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 __reverse_iterator<iterator, T&, T*> reverse_iterator;
		typedef __reverse_iterator<const_iterator, const T&, const T*> const_reverse_iterator;


		const_iterator begin() const
		{
			return const_iterator(_head->_next);
		}

		const_iterator end() const
		{
			return const_iterator(_head);
		}

		iterator begin()
		{
			return iterator(_head->_next);
		}

		iterator end()
		{
			return iterator(_head);
		}

		reverse_iterator rbegin()
		{
			return reverse_iterator(end());
		}

		reverse_iterator rend()
		{
			return reverse_iterator(begin());
		}

		void empty_init()
		{
			// 创建并初始化哨兵位头结点
			_head = new Node;
			_head->_next = _head;
			_head->_prev = _head;
		}

		template <class InputIterator>
		list(InputIterator first, InputIterator last)
		{
			empty_init();

			while (first != last)
			{
				push_back(*first);
				++first;
			}
		}

		list()
		{
			empty_init();
		}

		void swap(list<T>& x)
			//void swap(list& x)
		{
			std::swap(_head, x._head);
		}

		// lt2(lt1)
		list(const list<T>& lt)
		{
			empty_init();
			list<T> tmp(lt.begin(), lt.end());
			swap(tmp);
		}

		// lt1 = lt3
		list<T>& operator=(list<T> lt)
		{
			swap(lt);
			return *this;
		}

		~list()
		{
			clear();
			delete _head;
			_head = nullptr;
		}

		void clear()
		{
			iterator it = begin();
			while (it != end())
			{
				it = erase(it);
			}
		}

		void push_back(const T& x)
		{
			//Node* tail = _head->_prev;
			//Node* newnode = new Node(x);

			 _head          tail  newnode
			//tail->_next = newnode;
			//newnode->_prev = tail;
			//newnode->_next = _head;
			//_head->_prev = newnode;

			insert(end(), x);
		}

		void push_front(const T& x)
		{
			insert(begin(), x);
		}

		iterator insert(iterator pos, const T& x)
		{
			Node* cur = pos._node;
			Node* prev = cur->_prev;

			Node* newnode = new Node(x);

			// prev newnode cur
			prev->_next = newnode;
			newnode->_prev = prev;
			newnode->_next = cur;
			cur->_prev = newnode;

			return iterator(newnode);
		}

		void pop_back()
		{
			erase(--end());
		}

		void pop_front()
		{
			erase(begin());
		}

		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 iterator(next);
		}

	private:
		Node* _head;
	};

	
	void test()
	{
		list<int> ls;
		ls.push_back(1);
		ls.push_back(2);
		ls.push_back(3);
		ls.push_back(4);
		ls.push_back(5);
		ls.push_back(6);

		for (auto& e : ls)
		{
			cout << e << " ";
		}
		cout << endl;
		list<int>copy = ls;
		for (auto e : copy)
		{
			cout << e << " ";
		}
	}
}

test.cpp

#include"list.h"
#include<list>

int main(void)
{
	mudan::test();
	//list<int>ls;
	//ls.push_back(1);
	//ls.push_back(2);
	//ls.push_back(3);
	//ls.push_back(4);
	//ls.push_back(5);
	//ls.push_back(6);
	//for (auto e : ls)
	//{
	//	cout << e << " ";
	//}
	//cout << endl;
	//list<int>lt(ls);
	//for (auto e : lt)
	//{
	//	cout << e << " ";
	//}
	return 0;
}

疑问1:为什么在迭代器当中不需要写深拷贝、析构函数

1、因为迭代器就是希望做到浅拷贝,就是需要拿到地址而不是值,因为迭代器的修改是会影响对象中的内容的

2、因为迭代器并没有申请额外的空间,所以不需要析构,如果写了析构函数,那么调用一次迭代器那岂不是把对象都给销毁了😂😂😂

疑问2:为什么在迭代器当中需要三个模板参数?

其实这三个参数是被抽象出来的,__list_iterator<T, Ref, Ptr>等价于__list_iterator<T, T&, T>,其实在迭代器当中只有一个参数也可以正常推导,但是在list类当中只有一个参数就不行了,因为如果传递过来的是const修饰的类,然后用T&来接收的话会导致权限被缩小了,所以,为了解决这个const的问题,直接显示的定义模板参数*

typedef __list_iterator<T, T&, T> iterator;
typedef __list_iterator<T, const T&,const T
> const_iterator;**

Ref就是reference

Ptr就是pointer

疑问3:反向迭代器是怎么实现的?

反向迭代器其实就是利用正向迭代器实现的,重载一下++、–等操作符,不过逻辑上功能要反过来写

疑问4:为什么*解引用不直接返回当前值

因为begin()和end()的位置和正常实现的不一样

为什么要加一些不认识的typedef

		typedef bidirectional_iterator_tag iterator_category;
		typedef T value_type;
		typedef Ptr pointer;
		typedef Ref reference;
		typedef ptrdiff_t difference_type;

我也不知道,不加过不了编译,我太菜了😭😭😭😭😭😭

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

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

相关文章

LCD_1602 显示单个字符

目录 效果图&#xff1a;​ 硬件接线&#xff1a; 源代码&#xff1a; Lcd1602.c lcd1602.h main.c 硬件&#xff1a;lcd1602 51单片机 串口 软件&#xff1a;stc keil 效果图&#xff1a; 硬件接线&#xff1a; LCD1602 RW RS E 分别接51单片机的P25 P26 P27 LCD1602…

决策树分析特征重要性可视化无监督特征筛选

from sklearn.tree import DecisionTreeClassifierdtc DecisionTreeClassifier() # 初始化 dtc.fit(x_train, y_train) # 训练# 获取特征权重值 weights dtc.feature_importances_ print(>>>特征权重值\n, weights)# 索引降序排列 sort_index np.argsort(weights…

【学习】ChatGPT对问答社区产生了哪些影响?

引用 StackExchange 社区 CEO Prashanth Chandrasekar 的一篇博客标题 “Community is the future of AI”&#xff0c;引出本文的观点&#xff0c;即ChatGPT对问答社区产生了颠覆性影响&#xff0c;问答社区必须釜底抽薪、涅槃重生&#xff0c;但我们必须坚信“社区才是AI的未…

慎用QGraphicsDropShadowEffect绘制阴影,会导致部分控件一直resizeEvent、重新绘制

我的程序还在创作中&#xff0c;代码还只是UI部分&#xff0c;数据都是固定的&#xff0c;也没有定时刷新之类代码&#xff0c;样式也只是使用了一小部分。有一天我发现我在QTableWidget添加自定义控件的时候&#xff0c;效应特别慢&#xff0c;而自定义控件只是在鼠标进入或离…

活动策划大揭秘:如何制定执行方案

对于刚转行做活动策划的小白&#xff0c;我对你的建议&#xff0c;就是两个字“借鉴”&#xff01; 小白要写出一份优秀的活动策划与执行方案&#xff0c;“借鉴”其实是唯一的方式。 而且而且越资深&#xff0c;借鉴的越多。 当我是小白的时候&#xff0c;我做一个案子只看…

vue3模型代码

效果&#xff1a; 代码 <template><div class"json_box"><json-viewer :value"jsonData" :boxed"false" :expand-depth"5" :expanded"true" ></json-viewer></div> </template><sc…

哈利波特!AI动画已经这么稳定了?MJ控制角色统一性5种技巧;百度大模型Prompt开发与应用新课上线;SD进阶万字长文 | ShowMeAI日报

&#x1f440;日报&周刊合集 | &#x1f3a1;生产力工具与行业应用大全 | &#x1f9e1; 点赞关注评论拜托啦&#xff01; &#x1f916; 哈利波特动画视频&#xff0c;使用 TemporalNet 制作 img2img 动画 这是 Reddit 论坛小伙伴分享的自制动画&#xff0c;内容选自哈利波…

Apikit 自学日记:添加测试步骤-脚本步骤

脚本步骤 在流程测试用例界面&#xff0c;进入用例管理&#xff0c;点击 添加脚本[Javascript] 按钮&#xff1a; 进入编辑用例页面&#xff0c;点击 新API测试 新建一个 API 请求。 API 自动化测试平台为代码模式的测试用例设计了一套简单的API信息模板&#xff0c;因此只需要…

d3dx9_33.dll丢失怎么解决

d3dx9_33.dll的作用 在讨论如何修复d3dx9_33.dll丢失错误之前&#xff0c;我们首先需要了解d3dx9_33.dll的作用。d3dx9_33.dll是DirectX 9的一个核心文件&#xff0c;它是DirectX库的一部分&#xff0c;用于提供图形和多媒体功能支持。DirectX是由Microsoft开发的一组多媒体技…

java项目根据启动位置指定 log4j2日志输出到指定目录

痛点 我们在开发的 java 项目一般都会记录日志&#xff0c;日志输出位置通常使用相对路径记录到当前启动 jar 包的同一个父文件夹下面。 当我们使用像 jsch、ssh 这种远程启动 java 程序的时候会出现一个问题&#xff1a; 日志会输出到当前登录用户的目录下面&#xff08;如…

机器学习洞察 | 降本增效,无服务器推理是怎么做到的?

2022 年&#xff0c;无服务器推理受到了越来越多的关注。常见的推理方式包括实时推理、批量转换和异步推理&#xff1a; 实时推理&#xff1a;具有低延迟、高吞吐、多模型部署的特点&#xff0c;能够满足 A/B 测试的需求 批量转换&#xff1a;能够基于任务 (Job-based) 的系统…

故障排查:通过ssh远程执行命令时报错未找到命令

博客主页&#xff1a;https://tomcat.blog.csdn.net 博主昵称&#xff1a;农民工老王 主要领域&#xff1a;Java、Linux、K8S 期待大家的关注&#x1f496;点赞&#x1f44d;收藏⭐留言&#x1f4ac; 目录 故障详情问题原因解决方案命令使用全路径修改~/.bashrc 故障详情 最近…

设计模式 - 抽象工厂模式

学完工厂模式&#xff0c;才发现还有一个抽象工厂模式&#xff1b;学习后发现不论是通过接口方式、还是继承方式&#xff0c;都可以使用抽象工厂模式&#xff1b;但是个人建议更多的时候&#xff0c;我们可以优先考虑接口方式&#xff0c;毕竟 单继承&#xff0c;多实现 设计模…

HTML5基础语法与标签

一、 HTML5介绍 HTML5是什么&#xff1f; HTML5是超文本标记语言&#xff08;HTML&#xff09;的第五个主要版本&#xff0c;用于描述网页结构和呈现内容。它是到目前为止最新且最强大的HTML版本。 HTML5语法约定 1.标签是HTML语法中的基本单位&#xff0c;由尖括号 ​<>…

QT分屏按钮

效果&#xff1a;按钮弹出分屏选择 // gridpopwidget.h #ifndef GRIDPOPWIDGET_H #define GRIDPOPWIDGET_H#include <QWidget> #include <QMouseEvent>class GridPopWidget : public QWidget {Q_OBJECT public:explicit GridPopWidget(QWidget *parent nullptr);~…

MySQL第二天

MySQL第二天 文章目录 MySQL第二天一、第一题 题目二、第二题题目 一、第一题 题目 1、先创建该customers表 create table customers ( c_num int primary key auto_increment, c_name varchar(50), c_contact varchar(50), c_city varchar(50),c_birth datetime not null);2、…

java IO流(一) File类

File对象只能对文件进行操作&#xff0c;不能操作文件中的内容。 1 File对象的创建 要注意的是&#xff1a;路径中"“要写成”\“进行转义&#xff0c; 路径中”/"可以直接用&#xff0c;但是最好的是使用File.separator&#xff0c;它会根据系统的不同进行转化&a…

ROS:分布式通信

目录 一、前言二、方案2.1准备2.2配置文件修改2.3配置主机IP2.4配置从机IP2.5测试 一、前言 ROS是一个分布式计算环境。一个运行中的ROS系统可以包含分布在多台计算机上多个节点。根据系统的配置方式&#xff0c;任何节点可能随时需要与任何其他节点进行通信。 因此&#xff…

小白开酒吧前要做好的三件事

一、进行市场调研当你有开酒吧的想法时&#xff0c;首先要做的第一步就是市场调研&#xff0c;进行市场调研可以让你了解到该地区酒吧市场是否良好&#xff0c;对未来的经营&#xff0c;有着决定成败的帮助&#xff0c;同时市场调研也可以让你了解到周边什么类型酒吧最受欢迎&a…

PMP证书有什么用,考试条件是什么?

很多关注项目经理岗位的朋友都知道&#xff0c;一些企业的招聘信息经常会发布&#xff0c;很多招聘项目经理岗/PMO岗的岗位要求中都会有一条&#xff1a;持有PMP/软考等证书的优先。 其实面试的时候&#xff0c;可能两个候选人的经历、经验、期望薪资都差不多&#xff0c;那么…