反向迭代器:reverse_iterator的实现

news2024/11/15 15:43:29

目录

前言

特点

注意事项

实现

构造函数

功能函数

在list与vector中的使用

vector

list


前言

反向迭代器是一种在序列容器的末尾开始,并向前移动至序列开始处的迭代器。在C++中,反向迭代器由标准库中的容器类提供,比如vectorlistdeque等。它们允许程序员以逆序遍历容器中的元素。

以下是反向迭代器的一些特点:

特点

  1. 反向遍历:反向迭代器从序列的最后一个元素开始,逐步移动到第一个元素。
  2. 操作符重载:C++中的反向迭代器重载了递增(++)和递减(--操作符。递增操作使迭代器向序列的开始方向移动,而递减操作使其向序列的结束方向移动。
  3. 类型:反向迭代器的类型通常由容器类型加上reverse_iterator后缀表示,例如vector<int>::reverse_iterator

注意事项

  • 反向迭代器不支持所有的普通迭代器的操作,例如算术操作(加、减)。
  • 使用反向迭代器时,递增操作实际上是向序列的开始方向移动。
  • 在C++标准库中,并不是所有容器都支持反向迭代器。只有那些支持双向迭代器(BidirectionalIterator)或随机访问迭代器(RandomAccessIterator的容器才提供反向迭代器。这是因为反向迭代器需要能够向前和向后遍历容器,而这两种迭代器都支持这些操作。

需要逆序访问容器元素时,它们可以简化代码并提高效率

反向迭代器有const版本和非const版本,所以我们需要实现两个版本。

实现

反向迭代器由于与正向迭代器的行为相似,因此借鉴适配器的思想,用正向迭代器实现反向迭代器

同时我们增加两个模板参数Ref Ptr,作为const T&和Const T*的区分


template<class Iterator, class Ref, class Ptr>
class ReverseIterator

成员变量就是一个被适配的正向迭代器

private:
    Iterator _it;

构造函数

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

用传入的模板迭代器去初始化成员

功能函数

++ --


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

* ->两种解引用

为了实现对称,解引用时,解引用的是当前位置的下一个数据


	Ref operator*()	//内部去调用普通迭代器的解引用
	{
		Iterator cur = _it;
		return *(--cur);	//返回数据的引用,不能--_it,防止迭代器错位
	}

		//->也是一种解引用
	Ptr operator->()	//返回的其实是一个指针
	{
		return &(operator*());
	}

==    !=

迭代器的比较,看看成员参数是不是一个


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

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

在list与vector中的使用

vector

首先我们需要展开头文件

#include "reverse_iterator.h"    //反向迭代器头文件在此展开
 

然后利用typedef将迭代器重命名

typedef T* iterator;
typedef const T* const_iterator;
typedef Reverse_Iterator<iterator, T&, T*> reverse_iterator;
typedef Reverse_Iterator<const_iterator, const T&, const T*> const_reverse_iterator;

rbegin与rend

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

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

const_reverse_iterator rbegin() const
{
	return const_reverse_iterator(end());
}

const_reverse_iterator rend() const
{
	return const_reverse_iterator(begin());
}

其中const反向迭代器将调用const成员(end()、begin())

((((

题外话:

返回时,采用的是传值返回

自定义类型的传值返回通常是通过拷贝构造函数来实现的。当一个对象作为函数的返回值时,如果采用值返回的方式,函数内部会创建一个临时对象,这个临时对象是通过拷贝构造函数来初始化的,它是对返回对象的一个副本。这个副本具有常性(体现在引用时)

这里一个特例,这是一个匿名对象,具有常性,但是却可以调用非const成员函数。

示例:

class MyClass {
public:
    MyClass() {
        // 构造函数
    }

    MyClass(const MyClass& other) {
        // 拷贝构造函数
    }

    // 其他成员函数和成员变量...
};

MyClass createObject() {
    MyClass obj;
    // 对obj进行一些操作
    return obj; // 这里会调用拷贝构造函数来构造返回值
}

int main() {
    MyClass result = createObject(); // 接收返回值,同样会调用拷贝构造函数
    return 0;
}

在上述代码中,当createObject函数返回obj时,会调用MyClass的拷贝构造函数来构造一个临时对象,这个临时对象随后会被用来初始化main函数中的result对象。因此,在这个过程中至少会发生两次拷贝构造:一次是在函数返回时构造临时对象,另一次是在接收返回值时。

需要注意的是,现代编译器通常会对此类操作进行优化,比如返回值优化(NRVO,Named Return Value Optimization)或者拷贝省略(copy elision),从而避免不必要的拷贝,以提高性能。在C++11及以后的版本中,这种优化是被标准所允许的,甚至在某些情况下是强制的。

示例2:

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

产生临时对象后:

这个临时对象会在表达式结束时被销毁,但是因为这是在一个返回语句中,所以返回的对象会被用来初始化函数调用的结果。这样,当函数调用者接收这个返回值时,他们实际上是在接收一个复制构造的 iterator 临时对象,而不是原始的返回对象。接收时,会使用拷贝构造等手段完成接收。

))))

list

同样得展开头文件

#include "reverse_iterator.h"    //对应头文件内容在此展开

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;

Reverse_Iterator这个模板类已经在此文件中展开,因此在list类中可以直接使用这个类模板,并借助自身的成员去实例化这个模板类。 


		reverse_iterator rbegin() 
		{						//强调对称
			return reverse_iterator(end());		//借助end()迭代器构造反向迭代器
		}

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

		const_reverse_iterator rbegin() const	//const迭代器
		{
			return const_reverse_iterator(end());	//调用的是const函数end()
		}

		const_reverse_iterator rend() const
		{
			return const_reverse_iterator(begin());	
		}

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

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

相关文章

代码随想录八股训练营总结篇 2024年8月

代码随想录八股训练营总结篇 2024年8月 1. 报名初衷 ​ 随着秋招的临近&#xff0c;我意识到自己需要迅速提升各方面的技术能力。但是在准备过程中&#xff0c;我自己学习动力不足&#xff0c;常常难以坚持。为了找到一群志同道合的学习伙伴&#xff0c;共同营造学习氛围&…

Ubuntu上安装配置(jdk/tomcat/ufw防火墙/mysql)+mysql卸载

jdk安装 1.上传jdk压缩包 详情&#xff1a; 下载rz服务&#xff08;lrzsz&#xff09;&#xff1a;sudo apt install lrzsz(在主用户root就不用sudo)下载压缩包&#xff1a;rz 2.解压jdk压缩包 &#xff1a; 详情&#xff1a; 在压缩包所在位置&#xff08;解压压缩使用看Li…

算法基础-离散化

1、a数组可能存在重复元素 去重 排序 2、如何算出 x 离散化后的值 二分 1、add 和 query 记录每次填入的两个数 2、将位置 x 和每次询问的两个数 l 和 r 添加到 alls 进行排序去重 3、通过Collections.binarySearch映射&#xff08;一定能找到&#xff0c;不用判…

Tita:绩效管理 101

自 20 世纪初以来&#xff0c;管理已从基于等级制度、自上而下的僵化结构演变为新的敏捷思维环境&#xff0c;在这种环境中&#xff0c;员工被赋予权力&#xff0c;团队拥有更多自主权&#xff0c;以制定与公司战略相一致的正确绩效目标。 2010 年&#xff0c;尤尔根-阿佩洛&a…

鸿蒙版本号管理问题

1&#xff0c;情景一 23版本有一个方法getTestVersionName23&#xff0c;24版本有两个方法getTestVersionName23 ,getTestVersionName24&#xff0c;项目依赖23版本&#xff0c;可以使用24版本里面的方法&#xff0c;使用ohpm.list命令查看&#xff0c;版本号是24 2&#xff0c…

【Qt笔记】QTreeView控件详解

目录 引言 一、QTreeView的基本用法 1. 创建QTreeView 2. 设置数据模型 3. 展开和折叠节点 4. 处理用户交互 二、自定义数据模型 1. 继承QAbstractItemModel 2. 实现必要的方法 3. 使用自定义模型 三、自定义视图和委托 1. 自定义视图 2. 自定义委托 四、过滤与…

GPT-4 vs LLaMA3.1:核心技术架构与应用场景对比

目录 前言 一、GPT-4 的核心技术架构 1.1 Transformer 结构概述 1.2 GPT-4 的主要组成部分 1.3 GPT-4 的创新与改进 二、LLaMA3.1 的核心技术架构 2.1 模型概述 2.2 LLaMA3.1 的主要组成部分 2.3 LLaMA3.1 的创新与改进 三、GPT-4 和 LLaMA3.1 的主要差异 3.1 模型规…

遇到“Interpreter parsed an intent ‘xxx‘ which is not defined in the domain“报错

运行rasa shell的时候遇到如图报错&#xff1a; 从字面意思来看是这个”show_tasks”的intent没有在domain中定义。但是我打开domain.yml检查&#xff0c;domain里面是包含了这个intent的。那又是怎么回事呢&#xff1f; 遇到这个报错&#xff0c;不仅仅要检查domain.yml&…

c++ 红黑树(自平衡二叉搜索树)

目录 红黑树的概念 红黑树的由来 红黑树的性质 红黑树结点的定义 红黑树的插入 情况一&#xff1a;插入结点的叔叔存在&#xff0c;且叔叔的颜色是红色。 情况二&#xff1a;插入结点的叔叔存在且颜色是黑色 / 叔叔不存在&#xff0c; 情况A&#xff1a;p为g的左孩子&am…

Android 使用原生相机Camera在预览界面进行识别二维码或者图片处理

1 项目需求 最近项目中有个需求:使用原生相机在预览界面进行识别二维码和图片处理。其实这个需求不是很难,难在对预览画面的处理过程。 自己针对这个需求写了一个工具类,便于后续进行复盘,同时也分享给有类似需求的伙伴们。 2 遇到的问题 2.1 二维码识别成功率低 使用…

python网络爬虫(零)——认识网页结构

网页一般有三部分组成&#xff0c;分别是HTML&#xff08;超文本标记语言&#xff09;、CSS&#xff08;层叠样式表&#xff09;、JScript&#xff08;活动脚本语言&#xff09; 1.HTML HTML是整个网页的结构&#xff0c;相当于整个网站的框架。带“<”“>”符号都属于H…

Linux Grep案例

目录 一. 查询两个文件第一列的数据并去重二. 抽取日志中指定的字段三. 服务器指定时间点异常查询四. 从csv文件中抽取指定的数据五. 获取除了空白行和注释之外的部分 一. 查询两个文件第一列的数据并去重 &#x1f4da;file1.log 123 aaa 你好 345 bbb 我好 345 ccc 大家好 …

【最新华为OD机试E卷】空栈压数(200分)-多语言题解-(Python/C/JavaScript/Java/Cpp)

🍭 大家好这里是春秋招笔试突围 ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-E/D卷的三语言AC题解 💻 ACM金牌🏅️团队| 多次AK大厂笔试 | 编程一对一辅导 👏 感谢大家的订阅➕ 和 喜欢💗 🍿 最新华为OD机试D卷目录,全、新、准,题目覆盖率达 95% 以上,…

2024上海初中生古诗文大会备考:单选题真题和每道题独家解析

新的学年已经开始了&#xff0c;距离2024年初中生古诗文大会初选的线上自由报名选拔还有2个月&#xff08;官宣11月3日线上初选正式开赛&#xff09;&#xff0c;据好真题了解&#xff0c;有一些学校的老师已经开始准备校内选拔了&#xff0c;以古诗文大会作为一个抓手&#xf…

torch、torchvision、torchtext版本兼容问题

1、torch与torchtext版本兼容 参考torchtext PyPI 2、 torch与torchvision版本兼容 参考torchvision PyPI

喜羊羊做Python真题

以下内容&#xff0c;皆为原创&#xff0c;制作实属不易&#xff0c;感谢大家的关注和点赞。 一.全局变量和局部变量 首先&#xff0c;全局变量是ls和lt。我们可以看到&#xff0c;函数内部lt列表的值 赋值 给了ls的列表。在定义的函数里面&#xff0c;ls是局部变量&#xff…

云同步的使用

云同步技术是一种在多个设备或系统之间保持数据一致性的技术&#xff0c;它通常依赖于云存储服务来实现。在Java中&#xff0c;实现云同步功能通常需要与云服务提供商的API进行交互&#xff0c;如Amazon S3、Google Cloud Storage、Microsoft Azure Blob Storage等。 以下是一个…

报错:java:程序包org.springframework.boot不存在

Date: 2024.08.31 18:01:20 author: lijianzhan 简述&#xff1a;关于java:程序包org.springframework.boot不存在问题如何进行修复。 操作如下&#xff1a; 点击左侧菜单栏选择设置&#xff0c;弹框内选择构建,执行&#xff0c;部署----->构建工具点击Maven按键&#xf…

python实战三-提取Word数据到Excel

视频源码&#xff1a; 链接&#xff1a;https://pan.quark.cn/s/83db5bb15383 一个文件夹下有大量会议通知文件&#xff0c;为word文件&#xff0c;文件格式都是一致的&#xff0c;现在要将文件中的一些字段提取出来汇总到Excel文件中。 会议通知文件格式如下&#xff1a; 要提…

Arthas线上诊断神器-如何安装?

文章目录 一、快速安装 ✅二、springboot-启动器 ✅ 一、快速安装 ✅ 第一种方式&#xff1a;通过下载arthas-boot.jar&#xff0c;然后用 java -jar 的方式启动&#xff5e; 第一步、下载arthas-boot.jar curl -O https://arthas.aliyun.com/arthas-boot.jar如果下载速度比较…