C++初阶—完善适配器(反向迭代器)

news2024/10/7 20:37:16

 

目录

0. 前言

1、反向迭代器定义

2、反向迭代器需要实现的相关函数

3、反向迭代器分析

4、针对vector物理空间结构分析

5、针对list物理空间结构分析

6、反向迭代器适配器的实现及测试


0. 前言

本篇文章主要根据前面所实现的STL中支持迭代器的容器进行完善,使用了适配器原则,传递正向迭代器数据类型,从而实现反向迭代器。

STL六大组件中:包括容器(vector、list、queue、stack、string...)、配接器(容器适配器:queue、stack、deque和priority_queue)、迭代器(普通迭代器、const迭代器、反向迭代器、const反向迭代器)、仿函数(less、greater...)、算法(find、swap、sort、merge、reverse...)、空间配置器(allocator)!!!

1、反向迭代器定义

  1. 反向迭代器从容器的尾元素向首元素反向移动的迭代器
  2. 对于反向迭代器,其中递增递减的含义完全颠倒
  3. 递增时,会移动到前一个元素
  4. 递减时,会移动到后一个元素
  5. 解引用时,需要获取到所属位置的前一个元素
  6. ->操作时,获取前一个位置数据的地址

2、反向迭代器需要实现的相关函数

反向迭代器操作:

  • rbegin()——指向容器最后一个元素的下一个位置
  • rend()——指向首元素的位置
  • crbegin()——const反向迭代器
  • crend()——const反向迭代器

反向迭代器内部操作:

前置++、后置++、前置--、后置--、关系运算符!=、解引用*、操作符->等

3、反向迭代器分析

        在实现list容器时,由于物理空间不连续,在实现其正向迭代器时,单独封装了一个类,而string、vector存储数据的物理空间是连续的,底层操作的实际时指向数据位置的指针。

        因此,在实现反向迭代器时,难道我们要针对每个容器,在实现一个类吗?

        结合上节课容器适配器的学习,我们可以根据C++类模板,传递正向迭代器,并设置多个模板参数,用于根据所传模板参数的不同,实体为不同的类,从而实现const迭代器!!!通过传递模板参数正向迭代器,我们只需要定义一个迭代器对象,复用正向迭代器的操作即可!!!对于sting、vector会自动调用其迭代器普通操作,对于list重载操作符,自动调用其重载的操作符!!!

以上操作极大提高了反向迭代器的复用性、适配性,也可称为针对迭代器的反向迭代器适配器

4、针对vector物理空间结构分析

 

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

//迭代器
		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());
		}

        通过上述代码分析,可知rbegin()指向end()位置,rend指向begin()位置,因此遍历时,rebgin()++便调用正向迭代器所重载或默认的--,当rbegin() == rend()时,遍历结束!!!

        而由于rbegin()每次指向所需数据位置的下一个位置,因此重载反向迭代器*操作时,需要使用中间变量,中间变量拷贝构造和--操作,在使用*操作,便获取到所应遍历数据位置的数据!同时也不会改变this所指向的位置!!!

        

        在使用后置++,--操作时,需要记录前一次数据的迭代器,返回所记录的迭代器,在进行正向迭代器的反向操作

5、针对list物理空间结构分析

 根据上述分析,结合list再次进行分析,rbegin()指向头节点,rend()指向头节点的下一个位置

        

    template<class T, class Ref, class Ptr>
    struct __list_iterator {
            typedef __list_node<T> list_node;
            typedef __list_iterator<T, Ref, Ptr> iterator;

            list_node* _node;

            __list_iterator(list_node* node)
                :_node(node)
            {}
            bool operator!=(const iterator& it) const {
                return _node != it._node;
            }
            bool operator==(const iterator& it) const {
                return _node == it._node;
            }

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

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

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

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

        遍历时,rbegin()++即相当于end()--,通过在list正向迭代器重写的类,此时rbegin()便会反向便利、

        解引用,获取到当前节点的前一个结点的数据,直到遍历到rend()结束!!!而对rend()解引用,会获取到头结点的数据,因此反向迭代器适配器同时适用所有容器!!!

6、反向迭代器适配器的实现及测试

反向迭代器的实现:

namespace Thb {
	//复用、适配,迭代器适配器
	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;
		}
		RIterator operator++(int) {
			RIterator temp = *this;
			--_cur;
			return temp;
		}
		RIterator operator--(int) {
			RIterator temp = *this;
			++_cur;
			return temp;
		}

		Ref operator*() {
			Iterator temp = _cur;
			--temp;
			return *temp;
		}
		Ref operator*() const {
			Iterator temp = _cur;
			--temp;
			return *temp;
		}

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

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

反向迭代器的测试:

#include"list.h"
#include"vector.h"
#include"stack&&queue.h"
namespace std {
	void testListReverse() {
		int arr[] = { 3,2,7,6,0,4,1,9,8,5 };
		Thb::list<int> ls(arr, arr + sizeof(arr) / sizeof(arr[0]));
		Thb::list<int>::iterator it = ls.begin();
		while (it != ls.end()) {
			cout << *it << " ";
			++it;
		}
		cout << endl;

		auto rit = ls.rbegin();
		while (rit != ls.rend()) {
			*rit += 1;
			cout << *rit << " ";
			++rit;
		}
		cout << endl;

		const Thb::list<int> ls1 = ls;
		auto crit = ls1.rbegin();
		while (crit != ls1.rend()) {
			cout << *crit << " ";
			++crit;
		}
		cout << endl;
	}
	void testVectorReverse() {
		int arr[] = { 3,2,7,6,0,4,1,9,8,5 };
		Thb::vector<int> ls(arr, arr + sizeof(arr) / sizeof(arr[0]));
		Thb::vector<int>::iterator it = ls.begin();
		while (it != ls.end()) {
			cout << *it << " ";
			++it;
		}
		cout << endl;

		auto rit = ls.rbegin();
		while (rit != ls.rend()) {
			cout << *rit << " ";
				rit++;
		}
		cout << endl;

		const Thb::vector<int> ls1 = ls;
		auto crit = ls1.rbegin();
		while (crit != ls1.rend()) {
			cout << *crit << " ";
			crit++;
		}
		cout << endl;
	}
	void testConst() {
		int arr[] = { 3,2,7,6,0,4,1,9,8,5 };
		Thb::vector<int> ls(arr, arr + sizeof(arr) / sizeof(arr[0]));

		const Thb::stack<int, Thb::vector<int>> st(ls);
		cout << st.top() << endl;
	}
}

int main() {
	try {
		std::testListReverse();
		std::cout << std::endl << std::endl << std::endl;
		std::testVectorReverse();
		std::cout << std::endl << std::endl << std::endl;
		std::testConst();
	}
	catch (const std::exception& e) {
		std::cout << e.what() << std::endl;
	}
	return 0;

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

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

相关文章

Mysql数据库日志和数据的备份恢复(去看一看海吧)

文章目录 一、数据库备份的重要性二、数据库备份的分类1.物理备份&#xff1a;对数据库操作系统的物理文件&#xff08;如数据文件、日志文件等)的备份。2.逻辑备份&#xff1a;对数据库逻辑组件&#xff08;如表等数据库对象&#xff09;的备份&#xff0c;导出sql文件。3.完全…

被卖到 2w 的 ChatGPT 提示词 Prompt 你确定不想要吗?

有朋友说&#xff0c;用 ChatGPT 生成的文案刻板化&#xff0c;格式化&#xff0c;而且往往也不是我想要的。‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ 想要用好 ChatGPT 人工智能工具太难了&#xff0c;想一个好的提示词&#xff0c;也太不容易了&#xff0c;ChatGPT 就像一个宝藏…

3ds MAX绘制休闲椅

首先绘制一个长方形&#xff0c;并用上边两端点和底边中点绘制一个样条曲线 将上述曲线旋转复制&#xff0c;形成一个交叉的样条曲线&#xff0c;并移动两端点的位置&#xff0c;形成一上一下的结构 这就是休闲椅的大致形状 通过创建线将四个端点连接起来&#xff0c;形成空间…

UI组件——滑块简介

滑块控件是调整音量和亮度等设置的首选解决方案。它们立即生效&#xff0c;并允许用户通过移动手柄来微调值。滑块可以很好地达到目的&#xff0c;尤其是在精度不是很重要的情况下。 但是&#xff0c;这些控件可能会令人困惑&#xff0c;难以抓取并设置为精确值。另外&#xf…

人类智能的未来在于东西方智能的融合

有人认为&#xff1a;“只有时空的对齐&#xff0c;没有价值的对齐&#xff0c;智能或许就是智障”&#xff0c;即智能技术必须要与人类的价值观念和道德标准相一致&#xff0c;否则它所产生的结果可能会对人类社会造成负面影响。在现代社会中&#xff0c;智能技术已经越来越广…

【Elacticsearch】 分片副本机制,集群发现机制 ,负载机制,容错机制,扩容机制, 分片路由原理

集群发现机制 Elasticsearch采用了master-slave模式&#xff0c; ES会在集群中选取一个节点成为主节点&#xff0c;只有Master节点有资格维护全局的集群状态&#xff0c;在有节点加入或者退出集群的时候&#xff0c;它会重新分配分片&#xff0c;并将集群最新状态发送给集群中其…

Netty中的零拷贝机制

零拷贝机制(Zero-Copy)是在操作数据时不需要将数据从一块内存区域复制到另一块内存区域的技术,这样就避免了内存的拷贝,使得可以提高CPU的。零拷贝机制是一种操作数据的优化方案,通过避免数据在内存中拷贝达到的提高CPU性能的方案。 1.操作系统的零拷贝机制 操作系统的存储空间…

C++基础(5)——类和对象(3)

前言 本文主要介绍了C中类和对象的基本知识 4.3.1&#xff1a;成员变量和成员函数分开存储 只有非静态成员变量才属于类的对象上 C语言中结构体为空时使用sizeof&#xff08;&#xff09;打印的结果是0 C中类和结构体为空&#xff0c;用sizeof关键字可以算出是空类占1字节、…

OpenCV项目开发实战--图像识别和目标检测之(手写数字分类)

文末附基于Python和C++两种方式实现的测试代码下载链接 在本教程中,我们将使用 OpenCV 构建一个简单的手写数字分类器。一如既往,我们将分享用 C++ 和 Python 编写的代码。 最后两个帖子旨在提供了解基础知识所需的教育。这篇文章旨在提供成功实施图像分类器所需的培训。那么…

SpringBoot集成阿里云OSS实现图片存储服务

SpringBoot集成阿里云OSS实现图片存储服务 1、OSS概述2、账号申请2.1 购买服务2.2 创建Bucket 3、抽取模板工具OssProperties配置类OssTemplate模板对象AutoConfiguration配置类yml配置内容 4、测试 阿里云OSS&#xff08;Object Storage Service&#xff09;是一种强大的云存储…

ASO优化之关于应用商店的展示量

应用的展示数据代表应用在整个应用市场内的曝光次数&#xff0c;被展示的位置包括&#xff1a;首页精品推荐&#xff0c;搜索结果列表&#xff0c;应用详情页等。 应用的展示数据是衡量ASO搜索优化的关键指标。当关键词的覆盖数增加了&#xff0c;展示的次数没有增加&#xff…

【Nacos源码系列】服务注册的原理

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 文章目录 Nacos介绍服务注册客户端注册服务端 总结 Nacos介绍 Nacos是一个基于云原生的动态服务发现、配置管理和服务治理平台&#xff…

cppzmq编译和使用(ubuntu22.04)

libzmq libzmq&#xff0c;也称为 ZeroMQ&#xff0c;是一个高性能、异步消息传递库&#xff0c;用于构建分布式和并发系统。它提供了简单而强大的原语&#xff0c;使得开发者可以方便地在应用程序之间进行异步通信。 以下是对 libzmq 的详细介绍&#xff1a; 简介&#xff1…

VOC数据洞察在淘宝详情页的应用与实践

本专题共10篇内容&#xff0c;包含淘宝APP基础链路过去一年在用户体验数据科学领域&#xff08;包括商详、物流、性能、消息、客服、旅程等&#xff09;一些探索和实践经验&#xff0c;本文为该专题第二篇。 在商详页基于用户动线和VOC挖掘用户决策因子带来浏览体验提升&#x…

如何使用 PowerPoint 2021 制作演示文稿(PPT)?

软件安装&#xff1a;办公神器office2021安装教程&#xff0c;让你快速上手_正经人_____的博客-CSDN博客 引言 PowerPoint 是一款非常常用的演示文稿制作工具&#xff0c;它可以帮助您创建漂亮的幻灯片&#xff0c;展示您的想法和信息。如果您是 PowerPoint 的新手&#xff…

如何选择初始化向量【密码学】(5)

目录 一、分组算法如何计算 二、什么影响算法的安全性 三、密钥的使用次数限制 一、分组算法如何计算 分组算法包括3个部分&#xff1a;数据分组&#xff0c;分组运算和链接模式。 数据分组&#xff1a;将数据分割成加密函数能够处理的数据块&#xff0c;如果不能整分&#x…

【MYSQL篇】mysql不同存储引擎中索引是如何实现的?

前言 不同的存储引擎文件是不一样&#xff0c;我们可以查看数据文件目录&#xff1a; show VARIABLES LIKE datadir;每 张 InnoDB 的 表 有 两 个 文 件 &#xff08; .frm 和 .ibd &#xff09;&#xff0c; MyISAM 的 表 有 三 个 文 件 &#xff08;.frm、.MYD、.MYI&…

简单的PWN堆栈溢出的尝试

这是一道2018年西电CTF线下赛的一道ez_pwn的小题目&#xff0c;该题目为堆栈溢出漏洞的利用1 本次实验环境为 ubuntu 20.0.4 使用工具&#xff1a;GDB pwngdb 首先分析文件大致情况 checksec ez_pwn Arch: amd64-64-little 表示该二进制文件是 64 位的 。 RELRO: Partial R…

计算机网络课程设计——中小型网络工程设计

文件地址:https://github.com/Recursiondzl/Computer-Network github里面有课设文件&#xff0c;别白嫖&#xff0c;点个star哦 摘 要&#xff1a;本次计算机网络实践&#xff0c;完成了中小型网络工程设计与实现对计算机网络知识进行了系统的复习&#xff0c;实践能力获得了…

0基础学习VR全景平台篇第45篇:编辑器底部菜单- 关联场景功能操作

大家好&#xff0c;欢迎观看蛙色VR官方系列——后台使用课程&#xff01; 本期为大家带来蛙色VR平台&#xff0c;底部菜单—关联场景功能操作。 一、本功能将用在哪里&#xff1f; 关联场景&#xff0c;是某个场景下的子场景&#xff0c;也可以理解为VR漫游作品的三级分组&…