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

ops/2024/12/23 6:29:49/

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;}// ++itSelf& 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.ppmy.cn/ops/27788.html

相关文章

【C++之二叉搜索树】

C学习笔记---019 C之二叉搜索树1、二叉搜索树的简单介绍2、二叉搜索树的基本操作2.1、二叉搜索树的查找2.2、 二叉搜索树的插入2.3、二叉搜索树的删除 3、搜索二叉树的应用3.1、查找匹配3.2、查找比较大小 4、搜索二叉树的模拟实现5、搜索二叉树的性能分析 C之二叉搜索树 前言…

基于simulink的电弧炉模型建模与仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 5.完整工程文件 1.课题概述 基于simulink的电弧炉模型建模与仿真&#xff0c;输出电弧炉模型的电压曲线和电流曲线以及U-I分布图。 2.系统仿真结果 3.核心程序与模型 版本&#xff1a;MATLAB2022a 53 …

redis核心数据结构——跳表项目设计与实现(跳表结构插入数据、删除数据、展示数据)

数据的插入 首先来看需求 你的任务是实现 SkipList 类中搜索节点和插入节点的成员函数。 插入节点成员函数签名&#xff1a;int insert_element(const K key, const V value) 向跳表中插入一对数据&#xff0c;如果跳表中已存在该键值对&#xff0c;则不做任何操作&#xff…

【独立版】商城盲盒源码带uniapp(H5+小程序+APP三端)全开源

前端uniapp开源代码&#xff0c;可用HBuilder工具无限发行H5、小程序和打包app&#xff0c;后端PHP开源源码&#xff0c;支持二开。 内有安装搭建教程&#xff0c;轻松部署&#xff0c;搭建即可运营&#xff0c;内置永久免费更新地址&#xff0c;后续无忧升级。 【独立版】商…

strcov的常用方法

strconv包的常用方法 文章目录: 文章目录 strconv包的常用方法1.strconv的简介以及常用方法的汇总2.strconv常用方法的实际案例学习(1)Atoi与Ttoa(2)Parse系列(3)Format系列&#xff0c;都是将参数转换为指定格式的字符串操作(4)Append系列函数 1.strconv的简介以及常用方法的…

第11章 数据库技术(第一部分)

一、数据库技术术语 &#xff08;一&#xff09;术语 1、数据 数据描述事物的符号描述一个对象所用的标识&#xff0c;可以文字、图形、图像、语言等等 2、信息 现实世界对事物状态变化的反馈。可感知、可存储、可加工、可再生。数据是信息的表现形式和载体&#xff0c;信…

SSL通信、证书认证原理和失败原因

目录 SSL通信SSL认证原理SSL证书认证失败的原因分析 SSL通信 SSL通信指的是使用SSL&#xff08;Secure Sockets Layer&#xff09;协议进行的加密通讯。SSL是一种标准的安全技术&#xff0c;用于建立一个加密链接&#xff0c;确保从用户的浏览器到服务器之间的数据传输是私密和…

相机知识的补充

一&#xff1a;镜头 1.1MP的概念 相机中MP的意思是指百万像素。MP是mega pixel的缩写。mega意为一百万&#xff0c;mega pixel 指意为100万像素。“像素”是相机感光器件上的感光最小单位。就像是光学相机的感光胶片的银粒一样&#xff0c;记忆在数码相机的“胶片”&#xff…