通过设计list类深入理解iterator迭代器

从零实现C++ STL list:深入理解双向链表与迭代器设计 在C++标准模板库(STL)中,容器是数据结构的核心抽象,而链表作为一种基础且灵活的数据结构,其实现原理是理解STL设计哲学的关键。双向链表通过节点间的指针链接实现数据存储,支持在任意位置进行常数时间的插入与删除操作,这一特性使其在需要频繁增删数据的场景下具有独特优势。从工程实践角度看,理解其底层机制不仅能提升对内存管理和异常安全的认识,更是掌握迭代器抽象这一STL灵魂的必经之路。迭代器作为连接容器与算法的桥梁,其失效规则(如list迭代器在元素删除时仅自身失效)直接关系到程序的正确性与性能。通过手动实现一 阅读详情

title: 通过设计list类深入理解iterator迭代器
date: 2024-04-26 16:10:11
tags: C++ 类和对象
cover: https://picbed0521.oss-cn-shanghai.aliyuncs.com/blogpic/Date.jpg

原文及更多原创文章见我的网站: www.supdriver.top

前置博客:从构建一个Date类入门C++类与对象
设计模式介绍:TODO

Iterator迭代器实际上也是一种设计模式,它提供了一种方法顺序访问一个聚合对象中各个元素

下面先迅速地搓一个list类

template <class T>//先用模板创建一个节点类
struct ListNode
{
	T _val;
	ListNode<T>* _next;
	ListNode<T>* _prev;

	//提供全缺省的默认构造函数
	ListNode(const T& val = T()) :_val(val), _next(nullptr), _prev(nullptr) {}
};

//用ListNode构造list类

template <class T>
class list
{
	typedef ListNode<T> Node;//用typedef简化代码
public:
	list()//默认构造函数
	{
		_head = new Node;
		//维护两个指针
		_head->_next = _head;
		_head->_prev = _head;
	}

	void push_front(const T& val)//头插
	{
		Node* newnode = new Node(val);
		Node* next = _head->_next;//额外的指针,简化代码

		_head->_next = newnode;
		newnode->_prev = _head;
		newnode->_next = next;
		next->_prev = newnode;
	}

	void pop_front()//尾插
	{
		if (empty()) return;

		Node* cur = _head->_next;
		
		_head->_next = cur->_next;
		cur->_next->_prev = _head;
		delete cur;
	}

	bool empty() //判空
	{
		return _head->_next == _head;
	}

	//剩余代码自行补全
    //......
private:
	Node* _head;
};

list的迭代器

不同于vector底层的数据在内存中连续存储,可以用原生指针充当迭代器,例如typedef T* iterator

list的底层是链表,在内存中分散存储,是不能用原生指针来连续*访问的,所以为了解决这一复杂问题,
需要自己写一个iterator类

普通迭代器

template<class T>//迭代器也得用模板
struct __list_iterator
{
	typedef __list_iterator<T> Self;//简化代码
	typedef ListNode<T> Node;
	Node* _node;

	__list_iterator(Node* node) :_node(node) {}

	Self& operator++()//重载operator++
	{
		_node = _node->_next;
		return *this;
	}

	bool operator!=(const Self& it) const //重载!==,比较操作符记得加const
	{
		return _node != it._node;
	}

	T& operator*()//重载 *
	{
		return _node->_val;
	}
};

list类中添加如下代码

public:
	typedef __list_iterator<T> iterator;

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

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

通过如上修改,list已经支持普通迭代器,并且非const修饰的list已经支持范围for了

测试代码如下

int main()
{
	list<int> lst;
	lst.push_front(5);
	lst.push_front(4);
	lst.push_front(3);
	lst.push_front(2);
	lst.push_front(1);

	for (auto e : lst)
	{
		cout << e << " ";
	}
	return 0;
}

const迭代器

const list要能提供const_iterator,因此我们还要写一个const_iterator类…吗?

其实并不用,要利用好C++中的模板语法来大大提高代码的复用性,尤其像iterator和const_iterator这种差别不大的类,没必要每个都单独写一段代码

为此我们的__list_iterator只需要能用模板解决好二者的差异即可。而目前最大的问题是什么?是operator*()的返回值问题,一个是返回T&,另一个是const T&,其他的成员函数则基本没差别,所以不妨扩充一下模板参数,添加一个Ref类。

有变化的代码如下

template<class T,class Ref>//增加一个Ref参数
struct __list_iterator
{
	typedef __list_iterator<T,Ref> Self;//Self这里的原类也要加
	typedef ListNode<T> Node;
	Node* _node;

	__list_iterator(Node* node) :_node(node) {}

	Ref operator*()//直接返回Ref类
	{
		return _node->_val;
	}
};

list类也有相应变化

public:
	typedef __list_iterator<T,T&> iterator;//普通迭代器
	typedef __list_iterator<T,const T&> const_iterator;//const迭代器

    const_iterator begin() const //针对const指针的
	{
		return const_iterator(_head->_next);
	}

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

这样通过增加一个Ref模板参数,完成了对iterator和const_iterator的代码级统一(当然模板实例化出来是不一样的)

但别忘了迭代器还要提供->操作符的重载,而operator->()函数要返回不同的指针,所以我们如法炮制,再增加一个Ptr模板参数

有变化的代码如下

template<class T,class Ref,class Ptr>//增加一个Ptr参数
struct __list_iterator
{
	typedef __list_iterator<T,Ref,Ptr> Self;//Self相应更改

	Ptr operator->()//重载->
	{
		return &(_node->_val);
	}
};

list类也有相应变化

public:
	typedef __list_iterator<T,T&,T*> iterator;//普通迭代器
	typedef __list_iterator<T,const T&,const T*> const_iterator;//const迭代器

至此,list和__list_iterator的基本功能已基本完成,本篇的重点__list_iterator主要解决了两点问题

-为了应对list的迭代器的复杂性,单独为其构建一个__list_iterator类,并提供一系列的操作符重载
-为了提高代码的复用性,仅用一个__list_iterator类来typedef普通迭代器和const迭代器,我们增加了模板参数,最终模板变为template<class T, class Ref, class Ptr>

用普通迭代器构造const迭代器

有时候我们需要用普通迭代器构造const迭代器,于是可以给__list_iterator提供一个比较有意思的构造函数,
可以实现时而充当拷贝构造,时而充当满足上述的构造

代码如下

typedef __list_iterator<T,Ref,Ptr> Self;//再展示一遍Self的代码,便于下文对比
typedef __list_iterator<T,T&,T*> iterator;//指定普通迭代器,并用typedef简化代码

__list_iterator(iterator it) :_node(it._node) {}

-当模板参数为<T,T&,T*>时,Self和iterator相同,上段代码中的构造函数相当于拷贝构造

-当模板参数为<T,const T&,const T*>时,Self和iterator不同,Slef是const迭代器,iterator始终是普通迭代器,这个构造函数便能用普通迭代器构造const迭代器

小结

通过构造一个list类,我们使用到了更复杂的迭代器,使用了带3个模板参数的__list_iterator类定义普通迭代器和const迭代器,学习了如何利用模板参数提高代码的复用性,如何提供额外的构造函数使__list_iterator支持用普通迭代器构造const迭代器

C++ STL list模拟实现:从节点设计到迭代器封装与内存管理 在C++标准模板库(STL)中,容器是泛型编程的核心组件,它们通过封装底层数据结构,提供统一、安全的接口。链表作为一种基础数据结构,其双向链表实现(如std::list)支持高效的元素插入与删除,这源于其节点通过指针连接、无需连续内存存储的原理。这种设计在需要频繁增删元素的场景(如事件处理、缓存系统)中具有重要技术价值。理解其内部机制,尤其是迭代器的封装与内存管理,能帮助开发者编写更高效、健壮的代码。本文通过模拟实现一个简化版list,深入探讨节点结构、哨兵节点、迭代器类设计及拷贝控制等关键实现细节,并解析 阅读详情

相关推荐

C++ STL反向迭代器原理剖析:从list实现看迭代器适配器设计

迭代器是C++标准模板库(STL)中连接容器与算法的核心抽象,它定义了访问容器元素的统一接口。其设计基于迭代器概念,通过不同类别(如输入、输出、前向、双向、随机访问迭代器)支持不同操作能力。迭代器适配器是一种设计模式,它包装现有迭代器以改变其行为而不修改底层结构,这种模式体现了STL的泛型编程思想与零开销抽象原则。在工程实践中,反向迭代器作为典型的迭代器适配器,通过重载运算符将正向迭代器的操作逻辑反向映射,实现了容器元素的反向遍历功能。这种设计在需要从尾部向头部处理数据的场景中特别有用,例如逆向查找、反向输

weixin_30732487的博客 389

【C++】深入理解list迭代器的设计与实现

在STL容器中,list作为经典的双向链表容器,其迭代器设计体现了C++模板编程的精髓。本文将深入探讨如何从零开始设计一个符合STL规范的list迭代器,揭示其背后的设计哲学和技术细节。

yishaobai的博客 636

从零实现C++双向链表:深入理解STL list设计与迭代器原理

在C++标准模板库(STL)中,容器是数据结构的核心抽象,而双向链表(list)作为一种支持高效任意位置插入删除的序列容器,其实现原理是理解STL设计思想的关键。通过节点结构、指针链接和迭代器封装的技术组合,list实现了O(1)时间复杂度的插入删除操作。这种设计在需要频繁修改序列的场景中具有重要技术价值,如实现LRU缓存、撤销操作栈等。本文将聚焦于**哨兵节点**的巧妙应用和**迭代器失效**问题的处理,通过手动实现一个完整的list容器,深入探讨STL底层机制与C++内存管理实践。

weixin_33483304的博客 300

C++ 类模板三参数深度解析:从链表迭代器看类型推导与实例化(为什么迭代器类模版使用三参数?实例化又会是怎样?)

本文深入解析了C++双向链表迭代器设计中的三模板参数机制。通过拆解T(元素类型)、Ref(引用类型)和Ptr(指针类型)三个参数的协同作用,揭示了迭代器如何实现类型通用性和读写分离。文章从内存视角详细展示了模板实例化过程,对比了三参数与单参数设计的优劣,并通过完整实例演示了从定义到调用的全链路。这种设计模式体现了C++泛型编程的哲学,在保证类型安全和零开销的前提下,实现了一套代码支持多种数据类型的复用机制,为理解STL容器设计提供了重要参考。

2501_90200491的博客 1031

C++STL为什么要有const_iterator

const_iterator的一系列问题。

Veahlin 4390

Mac用户必看:Parallels Desktop 18.1.1最新破解版安装与优化全攻略(附资源)

本文为Mac用户提供Parallels Desktop 18.1.1的详细安装与优化指南,涵盖虚拟化技术选型、专业级配置流程及性能调优技巧。重点解析Parallels Desktop在图形加速、系统资源调度方面的核心优势,并分享生产力增强技巧与典型应用场景实战方案,帮助用户最大化利用这一高效虚拟化工具。

weixin_29240343的博客 824

LinkedList集合

LinkedList集合 ​ 底层是链表结构实现,查询慢、增删快 LinkedList集合的特有功能 特有方法 方法名 说明 public void addFirst(E e) 在该列表开头插入指定的元素 public void addLast(E e) 将指定的元素追加到此列表的末尾 public E getFirst() 返回此列表中的第一个元素 public ...

熊猫拿铁 474

MATLAB小白也能搞定!BCT脑网络分析工具箱安装与入门指南

本文为零基础用户提供了一份详尽的BCT脑网络分析工具箱安装与入门指南。从MATLAB环境配置、BCT工具箱下载与路径添加,到连接矩阵构建、节点度与聚类系数等基础指标计算,手把手带领神经科学研究者跨越编程门槛,快速掌握脑影像数据分析的核心流程。

threejs5artist的博客 1092

C++ string vector list迭代器设计

list的结构不像vector和string vector和string其储存数据的空间是连续的,list储存数据的空间是随机的。 vector和string的迭代器本质上是指针,其可以支持++ – *等操作。 为了让list也可以支持类似指针的行为,所以对list的迭代器进行了封装 先看string的迭代器: ...

dodamce的博客 379

从零构建Elasticsearch MCP代理:自然语言查询背后的技术揭秘

本文深入解析如何从零构建Elasticsearch MCP代理,实现自然语言查询的技术架构与实战应用。通过MCP协议与Elasticsearch的结合,系统能够将自然语言转换为精确的DSL查询,提升非技术用户的数据查询效率。文章详细介绍了核心架构、DSL生成引擎、端到端系统搭建及生产环境最佳实践,为开发者提供全面的技术指南。

lll78的博客 877

erdas监督分类(二)

去云 用一张没有云的影像替代有云影像 构建aoi图层 将云和云影编码合并 重编码工作 在监督分类做的差不多以后(纠正无误,无明显错误),就要对监督分类图像进行重编码和颜色调整。 在中选中Recode,对原来分类的地物类别进行重编码,(为彻底修改,记得备份)选中一列,在New Value输入新的编码,依次编码后点击应用apply,即可实现。 这时的图像如果是全黑的或者只有一两类的颜色也没有关系,新的编码覆盖掉了原来的编码,但是颜色并没有改变才会这样。可以点击图像,右击...

weixin_58968530的博客 958

【集合】重构自己的ArrayList

/** * 重构自己的ArrayList * 完成的功能有:add、remove、get、size和iterator * @author LGQ * */ /** * 先定义一个MyList接口,内部定义要实现的功能 */ public interface MyList { /** * 增加一个 * 1.判断集合是否已满 * 2.没满

技术|方法|思想 827

SCHUNK SVH五指灵巧手 | 熵洛智能

雄克仿真五指机械手产品系列可以如人手操作那般完美地完成抓取操作。电子装置完全集成于腕关节中,使五指机械手几乎可以完成所有的人体手部动作。凭借带有9个驱动器的运动指骨,机械手可高精度地 执行多种抓取操作。富有弹性的抓取表面确保了对物体的可靠抓取。除了开启抓取和操作任务的全新领域之外,雄克还为在五指机械手的手势基础上进行人与机器人的交流开创了无限可能。编辑切换为居中添加图片注释,不超过 140 字(可选)产品特点:机械手有左手或右手两种版本适合移动应用耗能低,使用 24 V DC 在腕关节处完整集成了控制、调节

ShannonTech的博客 1331

【C++】深入理解自定义 list 容器中的 list_iterator:迭代器实现详解

通过,我们实现了自定义list容器的标准遍历方式。总结封装节点指针通过持有list_node指针_node来访问和移动链表节点。重载操作符和->用于访问节点数据。++和--用于迭代器的前进和后退。==和!用于迭代器的比较。与listlist_node的关系依赖list_node实现节点移动和数据访问。list通过提供统一的接口,使链表可以通过迭代器进行遍历、插入和删除操作。通过,自定义的list容器具备了与 STL 容器一致的遍历能力,使链表在不连续内存结构中也可以支持标准的迭代器操作。

weixin_74837455的博客 4446

TC3XX - MCAL知识点(十三):IOM EB-tresos配置说明及代码浅析

输入输出监视器(IOM)驱动程序作为比较单元,检查系统外设输出的正确操作,这些输出可以作为监视功能的输入。监控功能需要通过配置IOM硬件来实现。它向SMU生成全局系统事件。IOM驱动程序初始化并控制微控制器的IOM单元。驱动程序还为用户提供初始化和设置IOM内部单元的阈值的服务。它还应该提供重置IOM内核的服务。应该提供该服务来组合单个或多个本地事件,以生成单个全局系统事件。IOM驱动程序严重依赖于初始化和配置。软硬件关系如下图缩写解释LAM逻辑分析模块ECM事件组合模块FPC。

梦想技术家 1802

手把手教你完成YOLOv10 PySide6目标检测界面搭建,使用Qt6设计YOLOv10检测系统,前台系统+后台管理系统开发实战,可用于大论文凑工作量或毕设必备,全网最详细教程

手把手教你完成YOLOv10 PySide6目标检测界面搭建,使用Qt6设计YOLOv10检测系统,前台系统+后台管理系统开发实战,可用于大论文凑工作量或毕设必备,全网最详细教程

在职AI算法工程师,擅长计算机视觉,YOLO目标检测、分割等,擅长web、pyqt界面可视化,好内容持续更新中,来这里跟大家一起学习,共同进步 1733

深入理解集合的迭代器 Iterator,为什么遍历数组时删除元素不能直接使用remove()方法而需要使用迭代器?

本文介绍了Java中Iterator迭代器的基本概念与使用方法。主要内容包括:1. Iterator接口的核心方法hasNext()和next()的作用;2. 通过ArrayList示例演示迭代器的创建与遍历过程;3. 使用迭代器时的注意事项:不会报索引越界异常、不会自动复位、每次循环只能调用一次next()方法、遍历时不能使用集合方法修改集合元素。文章重点解析了迭代器遍历时修改集合会抛出ConcurrentModificationException异常的底层原理(modCount机制)。

m0_70325779的博客 3015

SAP 物料主数据 Forecasting 视图,别把预测只当成一个数字字段

摘要(150字): SAP S/4HANA物料主数据的Forecasting视图常被忽视,但对依赖历史消耗规律的物料至关重要。该功能基于工厂维度的历史消耗数据,结合预测参数自动计算未来需求,动态调整重订货点和安全库存。预测模板(Forecast Profile)能标准化参数设置,而消耗数据(Consumption Values)的质量直接影响预测结果。预测值作为MRP输入,需注意保存操作才能生效。自动重订货点功能通过分析消耗波动和服务水平,实现库存策略的动态优化。Individual Forecast功能则

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1435

从零实现C++ STL list:深入理解双向链表、迭代器与哨兵节点设计

在数据结构与算法中,链表是一种基础且重要的线性数据结构,通过节点间的指针链接实现动态存储。其核心原理在于每个节点包含数据域和指针域,支持高效的插入与删除操作。在C++标准模板库(STL)中,std::list作为双向链表的实现,封装了迭代器抽象与资源管理机制,提供了稳定常数时间的元素增删能力,尤其适用于频繁修改但无需随机访问的场景。通过模拟实现一个完整的list类模板,开发者能透彻理解**迭代器失效规则**与**哨兵节点**的设计精妙之处,掌握模板泛型编程与异常安全实践,从而编写出更健壮、高效的C++代码。

weixin_30520015的博客 282

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

C++ list类

在C++标准库中,list是一个非常重要的容器类,它实现了双向链表的数据结构。本文将详细介绍C++中list的使用方法,包括其构造函数、迭代器、容量操作、元素访问以及修改操作等。此外,我们还将探讨list的迭代器失效问题,并通过模拟实现一个简单的list类来深入理解其底层工作原理。最后,我们将对比list与vector的优缺点,帮助读者在实际开发中根据需求选择合适的容器。

m0_74951730的博客 1392

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

迭代器的遍历iterator

public class TestIterator{ // 第一种: //iterator迭代List: public void TestIteratorList(){ List&lt;String&gt; list=new ArrayList(); //通过遍历将值加入到list当中 for(int i=0;i&lt;5;i++){ list.ad...

weixin_44435458的博客 404

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

从零实现C++链表:深入理解STL list设计与迭代器原理

链表作为一种基础数据结构,通过节点间的指针链接实现动态存储,其核心优势在于任意位置的O(1)插入删除操作。在C++标准模板库中,std::list采用双向链表结构,配合哨兵节点简化边界处理,其迭代器设计遵循RAII原则确保资源安全。理解list的内部机制对掌握内存管理、异常安全及STL设计哲学至关重要。通过手动实现list容器,开发者能深入探究迭代器失效规则、splice操作的指针优化等底层细节,这些知识在需要频繁中间修改的缓存管理、事务日志等场景中具有重要工程价值。本文以C++ list实现为例,剖析节点

weixin_34111790的博客 415

【Java】Java容器类(五),深入理解迭代器

建议整个系列一起看(更新中): 增强for: https://blog.youkuaiyun.com/qq_45495857/article/details/109410980 泛型:https://blog.youkuaiyun.com/qq_45495857/article/details/109410912 容器篇(一),宏观了解:https://blog.youkuaiyun.com/qq_45495857/article/details/109524162 容器篇(二),深入理解List集合类: https://blog.cs.

GengMS的博客 493

[Java] 迭代器的深入理解

迭代器的深入理解 我们为什么要提出迭代器 因为我们要使用一个特有的专业的类去遍历Collection集合,这个时候我们就提出了迭代器 首先我们要知道迭代器是什么? 迭代器是一种模式,我们称之为迭代器模式 我们可以使用两个接口完成迭代器模式: Iterator接口 — 对Collection接口的实现子类都可以进行遍历 ListIterator接口 – 只能对List接口实现子类进行遍历 ListIterator接口专门是对List接口实现类遍历的迭代器,ListIterator接口中有更多方法可

m0_57001006的博客 260

list与iterator用法实例

// list_.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include #include #include class Node { public: int id; Node(int _id){id = _id;}; }; int _tmain(int argc, _TCHAR* argv[]) {

Guyf的专栏 4680
上一篇: network初识计算机网络
下一篇: Rust 异步性能最佳实践:从理论到深度优化
supdriver
博客等级 码龄3年 192粉丝 40原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值