list的迭代器模拟实现和迭代器失效(续)

news2025/1/15 18:42:07

文章目录

  • list的迭代器
  • operator->
  • 普通迭代器和const迭代器
  • 迭代器模版
  • 迭代器失效
    • 析构
    • 拷贝构造
    • 赋值重载
  • initializer_list

list的迭代器

对迭代器进行封装,迭代器的指针还是4个字节,在物理上是一样的,但是底层是完全不同的
迭代器是浅拷贝,因为list是不属于迭代器的,迭代器只是进行访问(指针)

operator->

为了增强可读性,operator变为了一个->

T* operator->()
{
   // ->的优先级高于&
   return &_node->_data;
}
struct AA
{
	int aa1 = 1;
	int aa2 = 2;
};

void test_list2()
{
	list<AA> lt;
	lt.push_back(AA());
	lt.push_back(AA());
	lt.push_back(AA());
	lt.push_back(AA());
	lt.push_back(AA());

	list<AA>::iterator it = lt.begin();
	while (it != lt.end())
	{
		// *it解引用拿到的是AA对象,对象.进行访问
		//cout << (*it).aa1 << ":" << (*it).aa2 << endl;
		// it->返回的是指针,指针aa1看起来很奇怪
		// 其实是省略了一个->,it.operator()->
		//cout << it->aa1 << ":" << it->aa2 << endl;
		cout << it.operator->()->aa1 << ":" << it.operator->()->aa2 << endl;
		++it;
	}
	cout << endl;

普通迭代器和const迭代器

  • const_iterator是指向的内容不能修改
  • const iterator是指针本身不能修改,使用了这种迭代器的遍历是不能使用了
下面这两个就是指向的内容不能被修改,权限缩小了
const T& operator*()
{
	return _node->_data;
}

// ->
const T* operator->()
{
	return &_node->_data;
}
  • 普通迭代器(可读可写)
template<class T>
struct list_iterator
{
	typedef list_node<T> Node;
	typedef list_iterator<T> Self;
	Node* _node;

	// 构造
	list_iterator(Node* node)
		:_node(node)
	{}

	T& operator*()
	{
		return _node->_data;
	}

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

	Self& 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)
	{
		// *this是迭代器
		Self tmp(*this);
		_node = _node->_prev;

		return tmp;
	}

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

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

  • const迭代器(只读不能写)
// const_iterator
template<class T>
struct list_const_iterator
{
	typedef list_node<T> Node;
	typedef list_const_iterator<T> Self;
	Node* _node;

	// 构造
	list_const_iterator(Node* node)
		:_node(node)
	{

	}

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

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

	Self& 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)
	{
		// *this是迭代器
		Self tmp(*this);
		_node = _node->_prev;

		return tmp;
	}

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

	bool operator==(const Self& s) const
	{
		return _node == s._node;
	}
};
  • 按需实例化(调用了才会实例化)
    类模版是按照需求进行实例化,编译器对模版只是浅浅的扫描,有没有大的语法错误,细节不会检查出来
    细节比如:*it += 10 , 指向的内容不能被修改
// 按需实例化
template<class Container>
void print_container(const Container& con)
{
	typename Container::const_iterator it = con.begin();

	while (it != con.end())
	{
		// *it += 10;

		cout << *it << " ";
		++it;
	}
	cout << endl;

	for (auto ch : con)
	{
		cout << ch << " ";
	}
	cout << endl;

}

void test_list1()
{
	list<int> ls;

	ls.push_back(1);
	ls.push_back(2);
	ls.push_back(3);
	ls.push_back(4);
	ls.push_back(5);


	list<int>::iterator it = ls.begin();
	while (it != ls.end())
	{
		*it += 10;

		cout << *it << endl;
		++it;
	}
	cout << endl;

	for (auto ch : ls)
	{
		cout << ch << " ";
	}
	cout << endl;

    // 只有调用了print_container才会报错
    // 调用了模版才会实例化
    // const_iterator不能修改指向的内容
	print_container(ls);
}

迭代器模版

用模版实例化就不用写高度相似的两个迭代器了
只是这样的模版比较奇怪
实现了类模版给编译器,编译器根据参数不同实例化出两个不同的类
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

迭代器失效

  • list的insert迭代器不失效,不是连续的空间
// insert之后迭代器不失效
void test_list3()
{
	list<int> ls;

	ls.push_back(1);
	ls.push_back(2);
	ls.push_back(3);
	ls.push_back(4);
	ls.push_back(5);

	list<int>::iterator it = ls.begin();
	ls.insert(ls.begin(), 10);
	(*it) *= 11;

	for (auto e : ls)
	{
		cout << e << " ";
	}
	cout << endl;

}
  • erase以后迭代器失效

erase之后是野指针,++it

// 删除
iterator erase(iterator pos)
{
	// 不能删除哨兵位的头节点
	assert(pos != end());

	Node* cur = pos._node;
	Node* prev = cur->_prev;
	Node* next = cur->_next;

	prev->_next = next;
	next->_prev = prev;

	delete cur;
	--_size;

	return next;
}

it = ls.begin();
while (it != ls.end())
{
	if (*it % 2 == 0)
	{
		it = ls.erase(it);
	}
	else
	{
		++it;
	}
}
print_container(ls);

析构

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

void clear()
{
	// iterator it = _head->_next;
	auto it = begin();
	while (it != end())
	{
		it = erase(it);
	}
}

拷贝构造

void test_list4()
{
	list<int> ls;

	ls.push_back(1);
	ls.push_back(2);
	ls.push_back(2);
	ls.push_back(3);
	ls.push_back(4);
	ls.push_back(5);

	// 拷贝构造
	list<int> lt(ls);

	print_container(ls);
	print_container(lt);
}

赋值重载

// 赋值重载
// ls1 = ls3
list<T>& operator=(list<T> ls)
{
	swap(ls);
	return *this;
}

void swap(list<T>& ls)
{
	std::swap(_head,ls._head);
	std::swap(_size, ls._size);
}

// 赋值重载
lt = ls;
print_container(ls);
print_container(lt);

initializer_list

底层是两个指针,指向维护的数组,一个是指向开始位置的指针,一个是指向结束位置的指针

void func(const list<int>& ls)
{
	print_container(ls);
}

void test_list5()
{
	 std::list<int> lt1 = { 1,2,3,4,5,6 };
	 auto lt2 = { 1,2,3,4,5,6 };

	 // 直接构造
	 // 使用了初始化列表构造lt3
	 // C++11用初始化列表直接构造
	 list<int> lt3({ 1,2,3,4,5,6 });
	 // 隐式类型转换
	 list<int> lt4 = { 1,2,3 };
	 // 引用的是{1,2,3,4,5,6}隐式类型转化为list<int>的临时对象
	 const list<int>& lt5 = { 1,2,3,4,5,6 };

	 func(lt3);
	 func({1,2,3});
}

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

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

相关文章

一文通透OpenVLA及其源码剖析——基于Prismatic VLM(SigLIP、DinoV2、Llama 2)及离散化动作预测

前言 当对机器人动作策略的预测越来越成熟稳定之后(比如ACT、比如扩散策略diffusion policy)&#xff0c;为了让机器人可以拥有更好的泛化能力&#xff0c;比较典型的途径之一便是基于预训练过的大语言模型中的广泛知识&#xff0c;然后加一个policy head(当然&#xff0c;一开…

Easysearch Rollup 使用指南

背景 在现代数据驱动的世界中&#xff0c;时序数据的处理变得越来越重要。无论是监控系统、日志分析&#xff0c;还是物联网设备的数据收集&#xff0c;时序数据都占据了大量的存储空间。随着时间的推移&#xff0c;这些数据的存储成本和管理复杂度也在不断增加。 为了解决这…

FPGA EDA软件的位流验证

位流验证&#xff0c;对于芯片研发是一个非常重要的测试手段&#xff0c;对于纯软件开发人员&#xff0c;最难理解的就是位流验证。在FPGA芯片研发中&#xff0c;位流验证是在做什么&#xff0c;在哪些阶段需要做位流验证&#xff0c;如何做&#xff1f;都是问题。 我们先整体的…

[免费]SpringBoot+Vue新能源汽车充电桩管理系统【论文+源码+SQL脚本】

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的SpringBootVue新能源汽车充电桩管理系统&#xff0c;分享下哈。 项目视频演示 【免费】SpringBootVue新能源汽车充电桩管理系统 Java毕业设计_哔哩哔哩_bilibili 项目介绍 随着信息化时代的到来&#xff0…

如何选择多个视频文件

文章目录 1. 概念介绍2. 方法与细节2.1 实现方法2.2 具体细节 3. 示例代码4. 内容总结 我们在上一章回中介绍了"如何选择多个图片文件"相关的内容&#xff0c;本章回中将介绍如何选择视频文件.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 我们在前…

闲谭SpringBoot--ShardingSphere分布式事务探究

文章目录 0. 背景1. 未分库分表时2. 仅分表时3. 分库分表时3.1 不涉及分库表3.2 涉及分库表&#xff0c;且分库表处于一个库3.3 涉及分库表&#xff0c;且分库表处于多个库3.4 涉及分库表&#xff0c;且运行中某库停机 4. 小结 0. 背景 接上篇文章《闲谭SpringBoot–ShardingS…

【20250113】基于肌肉形变测量的连续步态相位估计算法,可自适应步行速度和地形坡度...

【基本信息】 论文标题&#xff1a;Continuous Gait Phase Estimation by Muscle Deformations with Speed and Ramp Adaptability 发表期刊&#xff1a;IEEE Sensors Journal 发表时间&#xff1a;2024年5月30日 【访问链接】 论文链接&#xff1a;https://ieeexplore.ieee.or…

快速上手 HarmonyOS 应用开发

一、DevEco Studio 安装与配置 1. DevEco Studio 简介 DevEco Studio 是 HarmonyOS 的一站式集成开发环境&#xff08;IDE&#xff09;&#xff0c;提供了丰富的工具和功能&#xff0c;支持 HarmonyOS 应用开发的全流程。 2. DevEco Studio 下载与安装 下载地址&#xff1a…

Vue如何构建项目

目录 1.安装Node.js 2.换源(建议) 3.选择一个目录 4.创建一个vue项目 5.验证是否成功 1.安装Node.js 安装18.3或更⾼版本的 Nodejs 点击下载->Node.Js中文网 node -v npm -v 安装好后在windows的cmd窗口下运行 如果能运行出结果就说明安装好了。 2.换源(建议) //…

HTML拖拽功能(纯html5+JS实现)

1、HTML拖拽--单元行拖动 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><…

初识算法和数据结构P1:保姆级图文详解

文章目录 前言1、算法例子1.1、查字典&#xff08;二分查找算法&#xff09;1.2、整理扑克&#xff08;插入排序算法&#xff09;1.3、货币找零&#xff08;贪心算法&#xff09; 2、算法与数据结构2.1、算法定义2.2、数据结构定义2.3、数据结构与算法的关系2.4、独立于编程语言…

Linux 多路径Multipath学习

文章目录 Linux 多路径Multipath学习1. 简介1.1 Multipath I/O 技术 2. Multipath安装与使用2.1 安装2.2 启动 3. scsi设备模拟器scsi_debug3.1 简介3.2 加载 scsi_debug3.3 查看 scsi_id3.4 配置多个模拟设备3.5 聚合多路径 4. 删除聚合和单设备4.1 删除mpath4.2 删除 scsi 设…

浅谈云计算06 | 云管理系统架构

云管理系统架构 一、云管理系统架构&#xff08;一&#xff09;远程管理系统&#xff08;二&#xff09;资源管理系统&#xff08;三&#xff09;SLA 管理系统&#xff08;四&#xff09;计费管理系统 二、安全与可靠性保障&#xff08;一&#xff09;数据安全防线&#xff08;…

Observability:利用 GCP Vertex AI 集成提升 LLM 可观察性

作者&#xff1a;来自 Elastic Ishleen Kaur•Muthukumar Paramasivam 随着组织越来越多地将 LLM 用于内容创建、检索增强生成 (Retrieval-Augmented Generation - RAG) 和数据分析等 AI 应用&#xff0c;SRE 和开发人员面临着新的挑战。监控工作流、分析输入和输出、管理查询延…

Node.js - Express框架

1. 介绍 Express 是一个基于 Node.js 的 Web 应用程序框架&#xff0c;主要用于快速、简便地构建 Web 应用程序 和 API。它是目前最流行的 Node.js Web 框架之一&#xff0c;具有轻量级、灵活和功能丰富的特点。 核心概念包括路由&#xff0c;中间件&#xff0c;请求与响应&a…

Linux Top 命令 load average 指标解读

前言 作为平台开发的同学&#xff0c;维护平台稳定性是我们最基本的工作职责&#xff0c;下面主要介绍下top 命令里 &#xff0c;load average 这个指标如何去衡量机器负载程度。 概念介绍 load average 是系统在过去 1 分钟、5 分钟、15 分钟 的平均负载&#xff0c;它表示运…

【大数据】机器学习------神经网络模型

一、神经网络模型 1. 基本概念 神经网络是一种模拟人类大脑神经元结构的计算模型&#xff0c;由多个神经元&#xff08;节点&#xff09;组成&#xff0c;这些节点按照不同层次排列&#xff0c;通常包括输入层、一个或多个隐藏层和输出层。每个神经元接收来自上一层神经元的输…

【day5】Redis持久化之AOF + Redis事务_锁机制

AOF是什么 以日志的形式来记录每个写操作(增量保存)&#xff0c;将 Redis 执行过的所有写指令记录下来(比 如 set/del 操作会记录, 读操作 get 不记录 只许追加文件但不可以改写文件 redis 启动之初会读取该文件重新构建数据 redis 重启的话就根据日志文件的内容将写指令从前到…

【Python】Python之locust压测教程+从0到1demo:基础轻量级压测实战(1)

文章目录 一、什么是Locust二、Locust 架构组成三、实战 Demo准备一个可调用的接口编写一个接口测试用例编写一个性能测试用例执行性能测试用例代码1、通过 Web UI 执行&#xff08;GUI模式&#xff09;2、通过命令行执行&#xff08;非GUI模式&#xff09; 小知识&#xff1a;…

Jaeger UI使用、采集应用API排除特定路径

Jaeger使用 注&#xff1a; Jaeger服务端版本为&#xff1a;jaegertracing/all-in-one-1.6.0 OpenTracing版本为&#xff1a;0.33.0&#xff0c;最后一个版本&#xff0c;停留在May 06, 2019。最好升级到OpenTelemetry。 Jaeger客户端版本为&#xff1a;jaeger-client-1.3.2。…