【c++】反向迭代器的探究实现

Alt

🔥个人主页Quitecoder

🔥专栏c++笔记仓

Alt

在list中我们实现了正向的迭代器,学习完优先级队列后,我们也对适配器模式有了一个深刻的理解,这篇文章基于这种模式下,实现各类容器的反向迭代器

目录

  • 1.引入:list的反向迭代器
  • 2.适配实现反向迭代器
      • 1. 构造函数:
      • 2. 解引用操作符 `operator*`:
      • 3. 成员访问操作符 `operator->`:
      • 4. 前置自增操作符 `operator++`:
      • 5. 前置自减操作符 `operator--`:
      • 6. 不等于操作符 `operator!=`:
      • 总结编译器处理:

1.引入:list的反向迭代器

首先来回顾一下我们实现list的正向迭代器:

	template<class T, class Ref, class Ptr>
	struct ListIterator
	{
		typedef ListNode<T> Node;
		typedef ListIterator<T, Ref, Ptr> Self;

		Node* _node;
		ListIterator(Node* node)
			:_node(node)
		{}
		// *it
		//T& operator*()
		Ref operator*()
		{
			return _node->_data;
		}
	
		// it->
		//T* operator->()
		Ptr operator->()
		{
			return &_node->_data;
		}
		// ++it
		Self& operator++()
		{
			_node = _node->_next;
			return *this;
		}
		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 Self& it)
		{
			return _node != it._node;
		}

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

在list类里面这样声明:

template<class T>
class list {
    // ... 省略其他代码 ...
public:
    typedef ListIterator<T, T&, T*> iterator;
    typedef ListIterator<T, const T&, const T*> const_iterator;

    // ... 省略其他代码 ...
};

为了实现一个反向迭代器,需要创建一个新的迭代器类,该类的增加(operator++)和减少(operator--操作符与标准迭代器的行为相反。也就是说,对于一个反向迭代器,operator++将会移动到前一个元素(_prev),而operator--将会移动到下一个元素(_next)。这意味着它将沿着相反的方向遍历列表。以下是如何定义一个ListIterator的反向版本的示例:

template<class T, class Ref, class Ptr>
struct ReverseListIterator
{
    typedef ListNode<T> Node;
    typedef ReverseListIterator<T, Ref, Ptr> Self;

    Node* _node;
    ReverseListIterator(Node* node)
        :_node(node)
    {}
    
    // 解引用操作符
    Ref operator*()
    {
        return _node->_data;
    }

    // 成员访问操作符
    Ptr operator->()
    {
        return &_node->_data;
    }

    // 前置自增操作符,移动到前一个元素
    Self& operator++()
    {
        _node = _node->_prev;
        return *this;
    }

    // 后置自增操作符,移动到前一个元素
    Self operator++(int)
    {
        Self tmp(*this);
        _node = _node->_prev;
        return tmp;
    }

    // 前置自减操作符,移动到下一个元素
    Self& operator--()
    {
        _node = _node->_next;
        return *this;
    }

    // 后置自减操作符,移动到下一个元素
    Self operator--(int)
    {
        Self tmp(*this);
        _node = _node->_next;
        return tmp;
    }

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

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

这里的ReverseListIterator和原来的ListIterator很相似,区别就在于迭代器前进(++)和后退(--)的方向相反

通常情况下,标准库容器(比如listvector)会有.rbegin().rend()方法来获取反向迭代器的开始和结束。为了实现类似的功能,需要在容器类中添加生成ReverseListIterator实例的方法:

typedef ReverseListIterator<T, T&, T*> reverse_iterator;
typedef ReverseListIterator<T, const T&, constT*>const_reverse_iterator;

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

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

2.适配实现反向迭代器

typedef ReverseListIterator<T, T&, T*> reverse_iterator;
typedef ReverseListIterator<T, const T&, constT*>const_reverse_iterator;

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

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

这种实现只是对原有类的一个修改,只是对list这个反向迭代器的实现,我们下面来实现另一种适配模式,我传入某一容器的正向迭代器来适配生成反向迭代器

比如传入List类的正向迭代器,适配出List的反向迭代器,传入vector正向迭代器,适配出vector的反向迭代器

template<class Iterator, class Ref, class Ptr>
	struct ReverseIterator
	{
		typedef ReverseIterator<Iterator, Ref, Ptr> Self;
		Iterator _it;
		ReverseIterator(Iterator it)
			:_it(it)
		{}
		Ref operator*()
		{
			Iterator tmp = _it;
			return *(--tmp);
		}
		Ptr operator->()
		{
			//return _it->;
			//return _it.operator->();

			return &(operator*());
		}
		Self& operator++()
		{
			--_it;
			return *this;
		}
		Self& operator--()
		{
			++_it;
			return *this;
		}
		bool operator!=(const Self& s)
		{
			return _it != s._it;
		}
	};
}

在这个模板代码示例中,ReverseIterator 类型是一个反向迭代器,它是基于提供的正向迭代器类型 Iterator 来实现的当使用 ReverseIterator 时,编译器将会按照模板代码的描述来生成一个特定于所使用迭代器类型的类实例。以下是各个操作符和成员函数的作用,以及编译器如何处理它们:

1. 构造函数:

ReverseIterator(Iterator it) : _it(it) {}

构造函数接收一个正向迭代器 it 并存储在 _it 成员变量中。编译器处理构造函数的方式与普通的构造函数相同

2. 解引用操作符 operator*

Ref operator*()
{
    Iterator tmp = _it;
    return *(--tmp);
}

这个操作符创建了 _it 的一个副本 tmp,然后对 tmp 应用前置自减 operator--,将其后移一位,然后解引用。对于反向迭代器而言,这意味着解引用的是当前位置之前的元素。

编译器生成了一个临时变量 tmp,调用了对应类型 Iterator 的前置自减 operator--,并调用了解引用 operator*。注意,由于这是一个底层实现细节,编译器有权优化这些步骤(如通过直接调用必要的函数)以优化性能

3. 成员访问操作符 operator->

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

这个操作符通过调用解引用操作符 operator* 来获取值的引用,然后取地址得到对应元素的指针

编译器会生成代码,使用上面定义的解引用操作符 operator* 来获取一个引用,然后获取该引用的地址

4. 前置自增操作符 operator++

Self& operator++()
{
    --_it;
    return *this;
}

对于反向迭代器来说,“自增”实际上会使内部正向迭代器 _it 自减。编译器调用 _it 的前置自减操作符 operator-- 并返回 *this 实现反向迭代器的自增操作

5. 前置自减操作符 operator--

Self& operator--()
{
    ++_it;
    return *this;
}

对于反向迭代器来说,“自减”实际上会使内部正向迭代器 _it 自增。编译器调用 _it 的前置自增操作符 operator++ 并返回 *this 实现反向迭代器的自减操作

6. 不等于操作符 operator!=

bool operator!=(const Self& s)
{
    return _it != s._it;
}

这个操作符比较两个反向迭代器,实际上它比较了内部正向迭代器 _it 是否不相等。

编译器根据 Iterator 类型生成了比较操作,这通常是调用 Iterator 给定的 operator!=

总结编译器处理:

本来每个容器都要写一个反向迭代器的累,但是自己写,太费劲了 本质写一个反向迭代器的类模板,给编译器传不同的容器的正向迭代器实例化,编译器帮助我们实例化出各种容器的对应反向迭代器

编写一个通用的反向迭代器类模板可以省去为每个容器单独定义反向迭代器的麻烦。C++ 标准库中的 std::reverse_iterator 就是这样一个通用的反向迭代器适配器。它接收一个正向迭代器作为模板参数,反转了其遍历方向,使得利用正向迭代器的容器可以很容易地提供反向迭代能力

使用类模板可以使得编译器根据你向模板传递的不同正向迭代器类型,为每个具体的容器类型生成对应的反向迭代器实例。这个通用反向迭代器适配器遵循了一种 编写一次,处处使用的原则,极大地提高了代码的复用性

例如,在 ReverseIterator 模板中,只要定义一次,就可以用来产生各种支持正向迭代器的容器的反向迭代器,如下所示:

std::vector<int> vec = {1, 2, 3, 4, 5};
ReverseIterator<std::vector<int>::iterator, int&, int*> rIt(vec.end());

// 使用反向迭代器遍历 vector
for (; rIt != ReverseIterator<std::vector<int>::iterator, int&, int*>(vec.begin()); ++rIt) {
    std::cout << *rIt << " ";
}

在这段代码中,ReverseIteratorstd::vector<int>::iterator 类型进行了实例化。实际上,因为 std::reverse_iterator 已经存在于标准库中,通常不需要自己写这个,并且可以直接这样使用

std::vector<int>::reverse_iterator rIt = vec.rbegin();
// 标准库已经提供 begin 和 end 了,不需要我们手动构建 ReverseIterator 实例
for (; rIt != vec.rend(); ++rIt) {
    std::cout << *rIt << " ";
}

本篇文章到此结束!!感谢大家阅读!!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【论文阅读笔记】TS2Vec: Towards Universal Representation of Time Series

【论文阅读笔记】TS2Vec: Towards Universal Representation of Time Series 摘要 这段文字介绍了一个名为TS2Vec的通用框架&#xff0c;用于学习时间序列数据的表示&#xff0c;可以在任意语义层次上进行。与现有方法不同&#xff0c;TS2Vec通过对增强的上下文视图进行层次化…

【论文阅读:Towards Efficient Data Valuation Based on the Shapley Value】

基于Shapley值的高校数据价值评估 主要贡献 提出了一系列用于近似计算Shapley值的高效算法。设计了一个算法&#xff0c;通过实现不同模型评估之间的适当信息共享来实现这一目标,该算法具有可证明的误差保证来近似N个数据点的SV&#xff0c;其模型评估数量为 O ( N l o g ( N…

Typora配置PicGo图床,将图片文件上传到gitee厂库,获取图片链接显示在md文件中

Typora配置PicGo图床&#xff0c;将图片文件上传到gitee厂库&#xff0c;获取图片链接显示在md文件中 创建Gitee创库和配置私人令牌 名字、路径、描述自己随便添&#xff0c;但是必须开源&#xff0c;链接才能可以访问&#xff1a; 进入偏好设置 > 图像 > 选择PicGo-Cor…

CAS 与 volatile

目录 CAS volatile 为什么无锁效率高 CAS 的特点 CAS AtomicInteger 内部并没有用锁来保护共享变量的线程安全。那么它是如何实现的呢&#xff1f; public void withdraw(Integer amount) {while(true) {// 需要不断尝试&#xff0c;直到成功为止while (true) {// 比如拿到…

基于Springboot+Vue的Java项目-入校申报审批系统开发实战(附演示视频+源码+LW)

大家好&#xff01;我是程序员一帆&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;Java毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计 &am…

算法入门<一>:C++各种排序算法详解及示例源码

1、排序算法 排序算法&#xff08;sorting algorithm&#xff09;用于对一组数据按照特定顺序进行排列。排序算法有着广泛的应用&#xff0c;因为有序数据通常能够被更高效地查找、分析和处理。 1.1 评价维度 运行效率&#xff1a;我们期望排序算法的时间复杂度尽量低&#xf…

sunshine+n2n+moonlight串流远程控制全教程

远程主机说明&#xff08;两台电脑不在同一局域网下&#xff09;&#xff1a; 控制台电脑 被控制电脑 所有工具下载地址&#xff1a;https://www.lanzouw.com/b00eepod7e 密码:1234 一、首先NTN组网 使用NTN技术创建虚拟局域网&#xff0c;实现设备之间的P2P连接。 NTN组网…

SpringBoot中阿里OSS简单使用

官方文档:Java跨域设置实现跨域访问_对象存储(OSS)-阿里云帮助中心 1.pom中引入依赖 <dependency><groupId>com.aliyun.oss</groupId><artifactId>aliyun-sdk-oss</artifactId><version>3.15.1</version> </dependency> 如…

区块链 | IPFS:Merkle DAG

&#x1f98a;原文&#xff1a;IPFS: Merkle DAG 数据结构 - 知乎 &#x1f98a;写在前面&#xff1a;本文属于搬运博客&#xff0c;自己留存学习。 1 Merkle DAG 的简介 Merkle DAG 是 IPFS 系统的核心概念之一。虽然 Merkle DAG 并不是由 IPFS 团队发明的&#xff0c;它来自…

模块六:模拟——1419.数青蛙

文章目录 题目描述算法原理解法&#xff08;模拟 分情况讨论&#xff09; 代码实现 题目描述 题目链接&#xff1a;1419.数青蛙 算法原理 解法&#xff08;模拟 分情况讨论&#xff09; 模拟⻘蛙的叫声。 当遇到 ‘r’ ‘o’ ‘a’ ‘k’ 这四个字符的时候&#xff0c;我…

c++容器与算法概述

容器与算法 每个标准库容器都提供了begin() end() 函数&#xff0c;分别返回容器的头部位置和尾部位置。 I/O 流 对于自定义的类型&#xff1a; struct Entry {std::string name;int number;};如果需要使用标准输出需要重载<< 运算符&#xff0c;特别注意&#xff1a…

ICMP详解

3 ICMP ICMP&#xff08;Internet Control Message Protocol&#xff0c;因特网控制报文协议&#xff09;是一个差错报告机制&#xff0c;是TCP/IP协议簇中的一个重要子协议&#xff0c;通常被IP层或更高层协议&#xff08;TCP或UDP&#xff09;使用&#xff0c;属于网络层协议…

结构分析的有限元法及matlab实现(徐荣桥)|【PDF教材+配套案例Matlab源码】

专栏导读 作者简介&#xff1a;工学博士&#xff0c;高级工程师&#xff0c;专注于工业软件算法研究本文已收录于专栏&#xff1a;《有限元编程从入门到精通》本专栏旨在提供 1.以案例的形式讲解各类有限元问题的程序实现&#xff0c;并提供所有案例完整源码&#xff1b;2.单元…

用栈实现队列——leetcode刷题

题目要求我们只用栈的基本操作 push to top 入栈&#xff0c;peek from top 返回栈顶元素&#xff0c;pop from top 移除并返回栈顶元素&#xff0c;size 栈的大小&#xff0c;is_empty 判断栈是否为空&#xff0c;这几个函数来实现队列&#xff0c;也就是说&#xff0c;我们在…

Linux字符设备驱动-详解与实操:驱动架构、设备树、Pinctrl子系统和GPIO子系统、platform、设备树下的platform

如何编写一个驱动程序&#xff1a; &#xff08;1&#xff09;确定主设备号 &#xff08;2&#xff09;定义自己的file_operations结构体&#xff1a; 包含对应的open(drv_open)/read(drv_read)等设备操作函数&#xff0c;需要到内核中去注册 &#xff08;3&#xff09;实现…

OpenAI最大对手推出iOS版APP 以期与ChatGPT展开竞争 | 最新快讯

财联社 5 月 2 日讯&#xff08;编辑牛占林&#xff09;美东时间周三&#xff0c;人工智能(AI)初创公司 Anthropic 宣布推出一款免费的移动端应用程序(APP)&#xff0c;不过目前仅有 iOS 版本。 这款应用名为 Claude&#xff0c;与 Anthropic 的大模型系列名字相同。Anthropic …

基于Python的在线学习与推荐系统设计与实现(论文+源码)-kaic

题目&#xff1a;在线学习与推荐系统设计与实现 摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本在线学习与推荐系统就是在这样的大环境下诞生&#xff0…

macbook文件管理,这款神器不得不说 macbook文件管理技巧 macbookpro文件管理软件

使用MacBook办公就是看重高效的特点&#xff0c;但很多时候随着使用时间的增长&#xff0c;MacBook上的文件也会越来越多&#xff0c;如果没有很好的管理方式&#xff0c;只会给日常的使用造成诸多不便。如何更好的搞定macbook文件管理呢&#xff0c;且看下面几个方法&#xff…

新势力4月交付量比拼:理想超问界夺冠,小米首月交付超七千辆 | 最新快讯

理想汽车超越问界夺下 4 月新势力交付量冠军。 5 月 1 日&#xff0c;各大造车新势力纷纷亮出最新成绩。新入局者小米汽车也准时发布了交付数据&#xff0c;在交付首月&#xff0c;同时又是非完整交付月&#xff0c;小米就交出了超七千辆的好成绩&#xff0c;在造车新势力中尚属…

ngrinder项目-本地调试遇到的坑

前提-maven mirrors配置 <mirrors><!--阿里公有仓库--><mirror><id>nexus-aliyun</id><mirrorOf>central</mirrorOf><name>Nexus aliyun</name><url>http://maven.aliyun.com/nexus/content/groups/public</ur…
最新文章