STL:list的模拟实现(迭代器失效探讨)

2023-10-31

为什么重新设计list迭代器

对迭代器解引用,我们希望拿到的是指针所指向的值域,而直接解引用拿到的是指针所指向的节点
**对list指针++和- -

迭代器:

  • 提供一种方法,使其能够按照顺序访问容器(聚合物)所含的各个元素,并且不用暴露容器内部的表述方式

本质

  • 就是指针或者对指针的封装

实现

  • 对原生态指针进行封装,即实现一个迭代器的类
  • 在容器中给迭代器取别名:typedef 迭代器类型 iterator
  • 在容器中增加begin和end的方法

使用:指针所具备的操作迭代器都需要有

  • *和->
  • 移动++,–
  • 比较==,!=

用户只和list类进行交互,在list类中实例化迭代器的模板

先构造list的每一个节点

template<class T>
struct ListNode
{
	ListNode* prev;
	ListNode* next;
	T val;

	ListNode(const T& value = T())
		:prev(nullptr)
		, next(nullptr)
		, val(val)
	{}
};

正向迭代器设计

typedef P P
在反向迭代器类中没有P和R类型,但是在正向迭代器中有,需要去找

template<class T, class P, class R>
struct ListIterator
{
	typedef P P;
	typedef R R;
	typedef ListNode<T> Node;
	typedef ListIterator<T, P, R> iterator;

	Node* _pNode;//成员变量

	ListIterator(Node* pNode=nullptr)
		:_pNode(pNode)
	{}
	
	R operator*()
	{
		return _pNode->val;
	}
	
	P operator&()
	{
		return &(_pNode->val);
	}
	
	iterator& operator++()
	{
		_pNode = _pNode->next;
		return *this;
	}
	
	iterator operator++(int)
	{
		iterator tmp(*this);
		_pNode = _pNode->next;
		return tmp;
	}
	
	iterator& operator--()
	{
		_pNode = _pNode->prev;
		return *this;
	}
	
	iterator operator--(int)
	{
		iterator tmp(*this);
		_pNode = _pNode->prev;
		return tmp;
	}
	
	bool operator!=(const iterator& it)const
	{
		return _pNode != it->_pNode;
	}
	
	bool operator==(const iterator& it)const
	{
		return _pNode == it->_pNode;
	}
};

反向迭代器

反向迭代器是通过正向迭代器实例化出来的

加typename的原因

  • P和R是在正向迭代器中的
  • 静态成员变量也是按照类名::静态成员变量名访问的
  • 如果不加typename修饰,编译器就不知道iterator后的是类型还是静态成员变量
template<class iterator>
struct rListIterator
{
	iterator _it;
	typename typedef iterator::R R;
	typename typedef iterator::P P;

	typedef rListIterator<iterator> riterator;
	
	R operator*()
	{
		iterator tmp = _it;
		tmp--;
		return *tmp;
	}

	P operator&()
	{
		return _it->_pNode->val;
	}

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

	riterator operator++(int)
	{
		_it--;
		return *this;
	}

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

	riterator operator--(int)
	{
		_it++;
		return *this;
	}

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

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

list类

template<class T>
	class list
	{
	private:
	    Node* _head;//成员变量
		void CreateHeadNode()
		{
			_head = new Node();
			_head->next = _head;
			_head->prev = _head;
		}
		
	public://确定类型,实例化模板类
		typedef ListNode<T> Node;
		typedef ListItertor<T, T*, T&> iterator;
		typedef ListItertor<T, const T*, const T&> const_iterator;

		typedef ListReverseIterator<iterator> reverse_iterator;
		typedef ListReverseIterator<const_iterator> const_reverse_iterator;

	public:
	//
	// 构造
		list()
		{
			CreateHeadNode();
		}

		list(int n, const T& val = T())
		{
			CreateHeadNode();
			for (int i = 0; i < n; ++i)
			{
				push_back(val);
			}
		}

		template<class Iterator>
		list(Iterator first, Iterator last)
		{
			CreateHeadNode();
			while (first != last)
			{
				push_back(*first);
				++first;
			}
		}

		list(const list<T>& L)
		{
			CreateHeadNode();
			for (auto e : L)
			{
				push_back(e);
			}
		}

		list<T> operator=(list<T> L)
		{
			this->swap(L);
			return *this;
		}

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

		/
		// 正向迭代器
		iterator begin()
		{
			return iterator(_head->next);
		}

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

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

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

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

		///
		// 容量相关
		size_t size()const
		{
			size_t count = 0;
			Node* cur = _head->next;
			while (cur != _head)
			{
				++count;
				cur = cur->next;
			}
			return count;
		}

		bool empty()const
		{
			return _head == _head->next;
		}

		void resize(size_t newsize, const T& val = T())
		{
			size_t oldsize = size();
			if (newsize < oldsize)
			{
				// 将原链表中节点个数缩减到newsize个
				for (size_t i = newsize; i < oldsize; ++i)
				{
					pop_back();
				}
			}
			else
			{
				// 将原链表中有效节点的个数增加到newsize个
				for (size_t i = oldsize; i < newsize; ++i)
				{
					push_back(val);
				}
			}
		}

		
		// 元素访问
		T& front()
		{
			return _head->next->val;
		}

		const T& front()const
		{
			return _head->next->val;
		}

		T& back()
		{
			return _head->prev->val;
		}

		const T& back()const
		{
			return _head->prev->val;
		}

		///
		// 修改
		void push_front(const T& val)
		{
			insert(begin(), val);
		}

		void pop_front()
		{
			if (empty())
				return;

			erase(begin());
		}

		void push_back(const T& val)
		{
			insert(end(), val);
		}

		void pop_back()
		{
			if (empty())
				return;

			auto pos = end();
			--pos;
			erase(pos);
		}

		iterator insert(iterator Itpos, const T& val)
		{
			Node* pos = Itpos._pNode;
			Node* newNode = new Node(val);
			newNode->next = pos;
			newNode->prev = pos->prev;
			newNode->prev->next = newNode;
			pos->prev = newNode;
			return newNode;
		}

		iterator erase(iterator Itpos)
		{
			Node* pos = Itpos._pNode;
			if (pos == _head)
				return pos;

			// 将pos节点从链表中拆除下来
			pos->prev->next = pos->next;
			pos->next->prev = pos->prev;

			Node* retNode = pos->next;
			delete pos;
			return retNode;
		}

		void clear()
		{
			Node* cur = _head->next;
			// 采用头删法
			while (cur != _head)
			{
				_head->next = cur->next;
				delete cur;
				cur = _head->next;
			}

			_head->next = _head;
			_head->prev = _head;
		}

		void swap(list<T>& L)
		{
			std::swap(_head, L._head);
		}
	};
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STL:list的模拟实现(迭代器失效探讨) 的相关文章

  • 在 C 语言中,为什么数组的地址等于它的值?

    在下面的代码中 指针值和指针地址与预期不同 但数组值和地址则不然 怎么会这样 Output my array 0022FF00 my array 0022FF00 pointer to array 0022FF00 pointer to a
  • 无法继承形状

    为什么我不能使用继承 a 的类Shapes class http msdn microsoft com en us library ms604615 28v vs 90 29 我需要延长Rectangle具有一些方法的类 但我想以与使用相同
  • strlen() 编译时优化

    前几天我发现你可以找到编译时strlen使用这样的东西 template
  • Selenium - C# - Webdriver - 无法找到元素

    在 C 中使用 selenium 我试图打开浏览器 导航到 Google 并找到文本搜索字段 我尝试下面的 IWebDriver driver new InternetExplorerDriver C driver Navigate GoT
  • 如何向 Mono.ZeroConf 注册服务?

    我正在尝试测试 ZeroConf 示例http www mono project com Mono Zeroconf http www mono project com Mono Zeroconf 我正在运行 OpenSuse 11 和 M
  • MVC 5 中具有 ASP.NET Identity 的 Autofac 不会验证 OWIN 管道中的安全标记

    我在 MVC 5 中设置了 AutoFac 来与 ASP NET Identity 一起使用 表面上一切似乎都工作正常 即用户可以创建帐户并登录 但后来我发现 当安全标记更改时 用户不会注销 通过在 AspNetUsers 表中进行暴力破解
  • OpenGL:如何检查用户是否支持glGenBuffers()?

    我检查了文档 它说 OpenGL 版本必须至少为 1 5 才能制作glGenBuffers 工作 用户使用的是1 5版本但是函数调用会导致崩溃 这是文档中的错误 还是用户的驱动程序问题 我正在用这个glGenBuffers 对于VBO 我如
  • Libev,如何将参数传递给相关回调

    我陷入了 libev 中争论的境地 通常 libev 在类似的函数中接收包 接收回调 没关系 但是实际操作中 我们需要派遣一个亲戚 写回调 根据收到的包裹处理具体工作 例如 S RECV MSG pstRecvMsg S RECV MSG
  • Linux 上的 RTLD_LOCAL 和dynamic_cast

    我们有一个由应用程序中的一些共享库构成的插件 我们需要在应用程序运行时更新它 出于性能原因 我们在卸载旧插件之前加载并开始使用新插件 并且只有当所有线程都使用旧插件完成后 我们才卸载它 由于新插件和旧插件的库具有相同的符号 我们dlopen
  • C# 获取数据表中所有重复行的计数

    我通过运行存储过程来填充数据集 并且从数据集中填充数据表 DataSet RawDataSet DataAccessHelper RunProcedure storedprocedureName this will just return
  • 对于 C# Express 用户来说,有哪些好的工具可以识别可能重复的代码? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 也可以看看 有什么工具可以检查重复的 VB NET 代码吗 https stackoverflow c
  • ASP.NET Core 中间件与过滤器

    在阅读了 ASP NET Core 中间件之后 我对何时应该使用过滤器以及何时应该使用中间件感到困惑 因为它们似乎实现了相同的目标 什么时候应该使用中间件而不是过滤器 9频道有一个关于此的视频 ASP NET 怪物 91 中间件与过滤器 h
  • 以编程方式创建 Blob 存储容器

    我有一个要求 即在创建公司时 在我的 storageaccount 中创建关联的 blob 存储容器 并将容器名称设置为传入的字符串变量 我已尝试以下操作 public void AddCompanyStorage string subDo
  • C++ 指针引用混淆

    struct leaf int data leaf l leaf r struct leaf p void tree findparent int n int found leaf parent 这是 BST 的一段代码 我想问一下 为什么
  • Streamwriter 覆盖 txt 文件中的文本

    有没有什么方法可以重新打开流写入器而不创建新的写入对象 因为此时 当调用 WriteOdd 时 streamwriter 正在覆盖在它之前调用的 WriteEven public void WriteEven StreamWriter wr
  • .Net Reactive Extensions Framework (Rx) 是否考虑拓扑顺序?

    Net 反应式扩展框架是否按拓扑顺序传播通知以最大限度地减少更新量 就像 Scala Rx 所做的那样 Net 反应式扩展 Rx 是否可以 https github com lihaoyi scala rx wiki How it Work
  • 声明一个负长度的数组

    当创建负长度数组时 C 中会发生什么 例如 int n 35 int testArray n for int i 0 i lt 10 i testArray i i 1 这段代码将编译 并且启用 Wall 时不会出现警告 并且似乎您可以分配
  • 如果找不到指定的图像文件,显示默认图像的最佳方式?

    我有一个普通的电子商务应用程序 我将 ITEM IMAGE NAME 存储在数据库中 有时经理会拼错图像名称 为了避免 丢失图像 IE 中的红色 X 每次显示产品列表时 我都会检查服务器中是否有与该产品相关的图像 如果该文件不存在 我会将其
  • ContentDialog Windows 10 Mobile XAML - 全屏 - 填充

    我在项目中放置了一个 ContentDialog 用于 Windows 10 上的登录弹出窗口 当我在移动设备上运行此项目时 ContentDialog 未全屏显示 并且该元素周围有最小的填充 在键盘上可见 例如在焦点元素文本框上 键盘和内
  • 嵌入式linux编写AT命令

    我在向 GSM 模块写入 AT 命令时遇到问题 当我使用 minicom b 115200 D dev ttySP0 term vt100 时它工作完美 但我不知道如何在 C 代码中做同样的事情 我没有收到任何错误 但模块对命令没有反应 有

随机推荐

  • python 点名随机+人脸识别

    基于tkinter写的随机点名窗口程序 运行截图 主窗口 点名操作 人脸识别操作 具体代码如下 主窗口 import random import tkinter import tkinter as tk import threading i
  • win7安装visual studio 2015出现安装包丢失或损坏

    win r 输入 certmgr msc 查看有没有选中的两个证书 如果没有需要从其他电脑导入 然后直接点击安装界面重试 即可继续安装
  • 海关爬虫7代(圣佛版)

    声明 代码仅作学习交流用途 代码分享者与创作者不承担任何由他人恶意运行而导致的责任 勿擅自修改限制频率的参数 勿恶意攻击网页 请学习浏览者遵守社会公德与法律秩序 爬虫导致的网页崩溃等损失由计算机操作者负全部责任 造成严重后果的需要承担刑事责
  • vue顶部菜单加左侧菜单_物流项目之用户登录、主页面、顶部菜单授权

    工程搭建分析 freight parent 父工程 打包方式pom 管理jar包的版本号 所有module都应该继承父工程 为什么不在freight parent定义所有jar包 而是定义版本号呢 项目部署到tomcat需要打war包 如果
  • hive中distribute by、sort by、cluster by

    1 背景 hive中有一个store表 字段分别是 商店所属人标识 merid 商户余额 money 商店名称 name 求每个法人下属的商店的余额按照降序排序 merid money name B 10 store B 4 A 12 st
  • 区块链技术2---BTC的数据结构

    1 Hash pointers 哈希指针 和普通指针相比 哈希指针除了保存地址还保存哈希值 2 Block chain 区块链中的区块通过哈希指针相连 这里的哈希指针的哈希值是对前一个区块的整体取哈希值 包括前一个区块的哈希指针 因此区块链
  • python3.7安装dlib (Wind10)

    使用pip install dlib 提示失败 原因 https pypi org project dlib files 查看说明最新版本dlib 19 20 0 不支持Python3 7 解决方案 整理了下网上说的方案大致如下 一 编译安
  • android 悬浮组件实现

    项目需求 需要实现一个每个页面都存在的悬浮按钮 可以拖动 跟随整个项目的生命周期 即应用登录之后显示悬浮按钮 应用退出之后 隐藏悬浮按钮 特殊页面隐藏悬浮按钮 应用后台展示之后 隐藏悬浮按钮 应用恢复前台展示 显示悬浮按钮 准备工作 添加权
  • js提示“没有权限”的问题(转载)

    当某个互联网运营商的网站上规模之后 他们都会考虑将网站部署到主域名相同 子域名不同的服务器集群上 以此来构建一个聚合的应用 同时 希望能够利用 JavaScript 在不同子域的网页间相互操作 实现一个对用户来说 无缝 的应用 这时 跨域操
  • 我是如何用 redis 分布式锁来解决线上历史业务问题的

    近期发现 开发功能的时候发现了一个 mq 消费顺序错乱 历史遗留问题 导致业务异常的问题 看看我是如何解决的 问题抛出 首先 简单介绍一下情况 线上 k8s 有多个 pod 会去消费 mq 中的消息 可是生产者发送的消息是期望一定要有序去消
  • HTML5 postMessage和跨域通信

    HTML5 postMessage和跨域通信 http iknowledge wikispaces com HTML5 postMessage E5 92 8C E8 B7 A8 E5 9F 9F E9 80 9A E4 BF A1 HTM
  • stm32cubemx hal学习记录:FreeRTOS中断管理

    一 参数配置 1 配置RCC USART1 时钟84M 2 配置SYS 将Timebase Source修改为除滴答定时器外的其他定时器 3 初始化LED的两个引脚 两个按键引脚 4 开启FreeRTOS v1与v2版本不同 一般选用v1即
  • 梯度下降法及其Python实现

    梯度下降法 gradient descent 又名最速下降法 steepest descent 是求解无约束最优化问题最常用的方法 它是一种迭代方法 每一步主要的操作是求解目标函数的梯度向量 将当前位置的负梯度方向作为搜索方向 因为在该方向
  • 轻松玩转开源大语言模型bloom(一)

    前言 chatgpt已经成为了当下热门 github首页的trending排行榜上天天都有它的相关项目 但背后隐藏的却是openai公司提供的api收费服务 作为一名开源爱好者 我非常不喜欢知识付费或者服务收费的理念 所以便有决心写下此系列
  • Vue3最常见的10道面试题:含答案和代码示例的练习题

    本文列举了10道Vue3面试题 每道题都包含了答案和代码示例 希望对你的面试有所帮助 什么是Vue3 Vue3是Vue js的下一个主要版本 它带来了很多重要的改进和新功能 包括更快的渲染速度 更好的类型支持 更好的组合API等 什么是Co
  • Postman 如何调用文件上传下载接口

    文件导入导出是管理后台的通用功能 所以在接口写好后在没有前端页面使用Postman进行接口调用测试接口功能成为一个选择 导出 在我们输入接口地址 token等候 点击send 发现下载的成为了乱码 如下图 这明显不符合我们的预期期望 在se
  • 文本分析简历项目收集-----机器学习(仅供参考)

    文本分析 项目3 基于自然语言处理的影评分析 项目简介 通过大量的正面和负面的电影评论对计算机进行自然语言训练 实现计算机对电影评论的基本情感分析 使其能够快速判断出评论是否积极 个人职责 1 对正面和负面的电影评论进行分词处理 整理成规定
  • 一次让人难以忘怀的排查频繁Full GC过程

    我们的Java应用因频繁FULL GC导致性能降低很多 经过多人的定位也没有结论 于是我自主请命 经过一天的研究终于搞定了 现把经验与大家共享 相关的gc日志如下 4 758 Full GC PSYoungGen 464K gt 0K 71
  • linux统计一个文件中特定字符的个数

    统计一个文件中某个字符串的个数 其实就是在在一块沙地里面找石头 有的人看到石头以后 在上面做个标记 grep 然后记住自己做了多少个标记 有的 人看到石头以后 把它挖了 tr 最后统计自己挖了多少石头 有的人看到石头以后 把它跳过去 awk
  • STL:list的模拟实现(迭代器失效探讨)

    为什么重新设计list迭代器 对迭代器解引用 我们希望拿到的是指针所指向的值域 而直接解引用拿到的是指针所指向的节点 对list指针 和 迭代器 提供一种方法 使其能够按照顺序访问容器 聚合物 所含的各个元素 并且不用暴露容器内部的表述方式