C++ STL全面解析:六大核心组件之一----迭代器(STL进阶学习)

 

目录

迭代器(iterator)

迭代器的分类

迭代器的使用

创建迭代器

迭代器的基本操作

使用迭代器遍历容器

迭代器的有效性和安全性

迭代器的类型

迭代器与算法

迭代器设计思维

迭代器的本质

文件 mylist-iter.h

文件 mylist-iter-test.cpp

迭代器相应类型


C++标准模板库(STL)是一组高效的数据结构和算法的集合,广泛应用于C++程序设计中。STL由六大核心组件组成,分别是:

  1. 容器(Containers):各种数据结构,如vector,list,deque等等。
  2. 迭代器(Iterators):扮演容器域算法之间的胶合剂,是所谓的”泛型指针“
  3. 算法(Algorithms):各种常用算法,例如sort,search,copy,erase等等。
  4. 函数对象(Function Objects):又名为仿函数,行为类似函数,可作为算法的某种策略。
  5. 适配器(Adapters):一种用来修饰容器或者仿函数或迭代器接口的东西,例如:stack和queue。
  6. 分配器(Allocators):负责空间配置域管理,从实现角度来看他是一个管理空间的模板类。

        STL六大组件的交互关系,容器通过分配器获取数据存储空间,算法则通过迭代器去存取容器的内容,(这也是为什么说迭代器是类似于一种胶合剂的角色),仿函数则可以协助算法完成不同的策略变化,适配器可以修饰或者套接仿函数。

迭代器(iterator)

迭代器可以被视为指向容器中元素的一个“指针”。它可以指向容器中的任意位置,并且提供了基本的指针操作,如递增(++)、递减(--)、解引用(*)等。迭代器作为我们日常编程中的常客之一,其重要性不言而喻。

注:以下内容部分参考自《STL源码剖析》。

迭代器的分类

迭代器可以根据功能的不同分为以下几类:

  1. 输入迭代器(Input Iterator):只能读取数据,支持前向移动(++)和解引用(*)操作。
  2. 输出迭代器(Output Iterator):只能写入数据,支持前向移动(++)和赋值(operator *)操作。
  3. 前向迭代器(Forward Iterator):结合了输入迭代器和输出迭代器的功能,支持前向移动(++)和解引用(*)操作。
  4. 双向迭代器(Bidirectional Iterator):除了前向迭代器的功能外,还支持反向移动(--)操作。
  5. 随机访问迭代器(Random Access Iterator):除了双向迭代器的功能外,还支持通过索引快速访问元素(operator[])。

迭代器的使用

创建迭代器

大多数标准容器(如 std::vector, std::list, std::map 等)提供了 begin()end() 成员函数来获取迭代器:

std::vector<int> vec = {1, 2, 3, 4, 5};
auto it_begin = vec.begin();  // 指向容器的第一个元素
auto it_end = vec.end();      // 指向容器的最后一个元素之后的位置
迭代器的基本操作

迭代器提供了以下基本操作:

  • 解引用(dereference):*it 获取迭代器指向的元素。
  • 递增(increment):++it 将迭代器移动到下一个元素。
  • 递减(decrement):--it 将迭代器移动到前一个元素。
  • 比较it1 == it2 或 it1 != it2 比较两个迭代器是否指向同一位置。
使用迭代器遍历容器

遍历容器中的元素通常使用迭代器来实现:

std::vector<int> vec = {1, 2, 3, 4, 5};// 使用迭代器遍历
for (auto it = vec.begin(); it != vec.end(); ++it) {std::cout << *it << std::endl;
}// 使用范围 for 循环(C++11 及以上版本)
for (const auto& element : vec) {std::cout << element << std::endl;
}

迭代器的有效性和安全性

迭代器的有效性是指迭代器是否仍然指向容器中的有效元素。如果容器发生改变(如插入或删除元素),迭代器可能会变得无效。例如:

std::vector<int> vec = {1, 2, 3, 4, 5};
auto it = vec.begin();// 插入一个元素会导致迭代器失效
vec.insert(it, 0);// 此时 it 可能不再有效

为了保证迭代器的安全性,通常需要在操作容器之前检查迭代器的有效性,并在容器改变后重新获取迭代器。

迭代器的类型

C++ 标准库中的容器提供了特定类型的迭代器,可以通过类型别名方便地访问:

std::vector<int>::iterator it;  // 随机访问迭代器
std::list<int>::iterator it;    // 双向迭代器
std::map<int, int>::iterator it;// 双向迭代器
std::set<int>::iterator it;     // 双向迭代器

迭代器与算法

C++ 标准库中的算法(如 std::sort, std::find, std::reverse 等)通常接受迭代器作为参数,允许在不同类型的容器上使用相同的算法:

std::vector<int> vec = {3, 1, 4, 1, 5, 9, 2, 6};
std::sort(vec.begin(), vec.end());  // 排序int value = 2;
auto it = std::find(vec.begin(), vec.end(), value);  // 查找if (it != vec.end()) {std::cout << "Found " << value << " at position " << std::distance(vec.begin(), it) << td::endl;
}

迭代器设计思维

        首先我们要知道STL设计时的中心思想:在使用时将容器和算法分开来,彼此独立设计,但是我如果想让容器使用算法怎么使用?迭代器就是两者之间的粘合剂。这个不难理解,我们日常在编程中会用到大量的例子。例如我们创建了个vector,我们可能会用到sort等算法,我们通常的做法就是把vector的头尾迭代器发给find,然后即可查找。例图如下

        现在我们知道迭代器是容器和算法之间的粘合剂,但是表面看来迭代器貌似是依附于容器的一个指针对吧。但是它只能依附于容器之下吗?是否有一些独立的用途?

迭代器的本质

        迭代器本质上可以视为一种智能指针。虽然迭代器具备普通指针的基本操作,如 ++--,但迭代器内部封装了更多的细节和检查机制,使其更加安全和易于使用。智能指针则是一种用于包装原生指针的对象,它能够有效地管理内存,防止内存泄漏。智能指针的用法如下,和原生指针一摸一样。

        上面意思是,首先是new了一个处置为jjhou的string对象,然后用auto_ptr<string>类型的指针指向了这个对象。注意:auto_ptr括号内放的是“原生指针所指对象”的型别,而不是原生指针的型别。

        如果我们自己设计一个迭代器的话该如何设计呢?首先我们需要有一个迭代器的模板。

        有了模仿对象后,我们现在以List为例设计一个迭代器。假设list的结构如下:

                如果让这个list与算法结合到一起呢?没错,那就是设计一个迭代器让他们粘合在一起。当我们获取迭代器是传回来的应该是一个ListItem的一个对象,递增是则指向下一个ListItem对象,反之递减。为了让我们的迭代器去适合任何类型的节点,这里设计时我们需要用到class template。

文件 mylist-iter.h

#ifndef MYLIST_ITER_H
#define MYLIST_ITER_H#include "mylist.h"template<class Item>
struct ListIter {  // 这个迭代器特定只为链表服务,因为其独特的 operator++Item* ptr;  // 保持与容器之间的一个联系(保持对容器的引用)ListIter(Item* p = nullptr) : ptr(p) {}  // 默认构造函数// 不必实现 copy ctor,因为编译器提供的缺省行为已足够// 不必实现 operator=,因为编译器提供的缺省行为已足够Item& operator*() const { return *ptr; }Item* operator->() const { return ptr; }// 以下两个 operator++ 遵循标准做法,参见 [Meyers96] 条款 6// (1) 前缀递增操作ListIter& operator++() {ptr = ptr->next;return *this;}// (2) 后缀递增操作ListIter operator++(int) {ListIter tmp = *this;++(*this);return tmp;}bool operator==(const ListIter& i) const {return ptr == i.ptr;}bool operator!=(const ListIter& i) const {return ptr != i.ptr;}
};#endif // MYLIST_ITER_H

文件 mylist-iter-test.cpp

  此文件中我们把List和Find由ListIter粘合起来.

#include "mylist.h"
#include "mylist-iter.h"
#include <iostream>void main() {List<int> mylist;// 插入元素for (int i = 0; i < 5; ++i) {mylist.insert_front(i);mylist.insert_end(i + 2);}// 输出列表std::cout << "List contents: ";mylist.display();std::cout << std::endl;// 创建迭代器ListIter<ListItem<int>> begin(mylist.front());ListIter<ListItem<int>> end(nullptr);  // 默认为 nullListIter<ListItem<int>> iter;// 查找元素iter = find(begin, end, 3);if (iter == end) {std::cout << "Not found" << std::endl;} else {std::cout << "Found: " << iter->value() << std::endl;}// 再次查找元素iter = find(begin, end, 7);if (iter == end) {std::cout << "Not found" << std::endl;} else {std::cout << "Found: " << iter->value() << std::endl;}
}

        从上方的一些实现细节我们可以看出,为了完成一个针对List而设计的迭代器,我们会暴露很多List实现细节。例如在制作begin和end时就暴露了ListItem。这在我们日常编程时可能没有什么太大的关系,但是在STL中这是一件非常不好的事,可能会影响一些封装性等。既然无可避免,那不如把List迭代器的开发工作交给List的创作人即可,这样实现细节可以最大性质的被封装起来。这也是为什么每种STL容器都有各自专属的迭代器。

迭代器相应类型

        在算法中使用迭代器时,很可能会用到其相应型别。什么是相应型别呢?迭代器所指之物的类型就是相应型别其一。假设算法中需要声明一个相应型别类型的变量那该怎么办?毕竟C++没有typeof()!

        解决办法是:利用function template的参数推导机制。

        我们以 func() 作为对外的接口,但实际的操作则委托给 func_impl()。由于 func_impl() 是一个函数模板,一旦被调用,编译器会自动进行模板参数推导,从而确定类型 T,从而顺利解决问题。

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

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

相关文章

多线程学习篇三:共享带来的问题及解决方案

1. 共享带来的问题 1.1 案例演示 两个线程对初始值为 0 的静态变量一个做自增&#xff0c;一个做自减&#xff0c;各做 5000 次&#xff0c;结果是 0 吗&#xff1f; Slf4j(topic "c.Sync01") public class Sync01 {private static int COUNTER 0;public static…

一次渲染十万条数据:前端技术优化(上)

今天看了一篇文章&#xff0c;写的是一次性渲染十万条数据的方法&#xff0c;本文内容是对这篇文章的学习总结&#xff0c;以及知识点补充。 在现代Web应用中&#xff0c;前端经常需要处理大量的数据展示&#xff0c;例如用户评论、商品列表等。直接渲染大量数据会导致浏览器性…

【C++登堂入室】类和对象(下)

目录 一、 再谈构造函数 1.1 构造函数体赋值 1.2 初始化列表 1.3 explicit关键字 二、static成员 2.1 概念 2.2 特性 三、友元函数 3.1 友元函数 3.2 友元类 四、内部类 五、 再次理解类和对象 结尾 一、 再谈构造函数 1.1 构造函数体赋值 在创建对象时&#xf…

【C++】多态的认识和理解

个人主页 文章目录 ⭐一、多态的概念&#x1f384;二、多态的定义及实现1.多态的构成2.实现多态的条件3.虚函数的概念4.虚函数的重写和覆盖5.析构函数的重写6.协变7.override和 final关键字8.重载、重写/覆盖、隐藏这三者的区别 &#x1f3e0;三、纯虚函数和抽象类的关系&#…

三目运算及简单案例

//三目运算是用来简化判断的 //所谓的三目 有三个表达式组成 //表达式一 条件表达式 返回的结果是布尔 //表达式二 条件表达式结果为true 时 返回的结果 //表达式三 条件表达式结果为false 时 返回的值 int age 20; //获取用…

树莓派驱动之spi回环测试

开启spi sudo raspi-config选择Interfacing options,选择spi打开 lsmod可以看到spi_bcm2835 短接MISO和MOSI 编写回环代码spitest.c #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <fcntl.h> #include <string.h>…

【Python机器学习】NLP信息提取——命名实体与关系

我们希望计算机能够从文本中提取信息和事实&#xff0c;从而略微理解用户所说的内容。例如&#xff0c;当用户说“提醒我星期一浏览***.org网站”&#xff0c;我们希望这句话触发当天后下一个周一的日程或者提醒的操作。 要触发上述操作&#xff0c;需要知道“我”代表一种特定…

【devops】devops-gitlab之部署与日常使用

本站以分享各种运维经验和运维所需要的技能为主 《python零基础入门》&#xff1a;python零基础入门学习 《python运维脚本》&#xff1a; python运维脚本实践 《shell》&#xff1a;shell学习 《terraform》持续更新中&#xff1a;terraform_Aws学习零基础入门到最佳实战 《k8…

新任项目经理,如何快速接手项目

新任项目经理踏上管理岗位&#xff0c;面临着前所未有的挑战与机遇。如何快速适应角色&#xff0c;有效管理团队&#xff0c;确保项目顺利推进&#xff0c;是每一位新任项目经理必须面对的。 一、深入了解项目与团队 1、项目定位与规划 新任项目经理应对项目进行全面的调研与…

初识zookeeper

Zookeeper介绍 Zookeeper是Apache Hadoop项目下的一个子项目&#xff0c;是一个树形目录服务。 Zookeeper是一个分布式的、开源的分布式应用程序的协调服务。 Zookeeper提供的主要功能包括&#xff1a; 配置管理分布式锁集群管理 Zookeeper数据模型 Zookeeper客户端常用命…

windows使用tcpdump.exe工具进行抓包教程

windows主机安装一些抓包工具可能有些不方便&#xff0c;这里有一个tcpdump.exe工具直接免安装&#xff0c;可以直接使用进行抓包。&#xff08;工具下载见 附件&#xff09; tcpdump.exe使用教程 如下&#xff1a; 1&#xff1a;tcpdump -D 可查看网络适配器(注意前面的编号)…

分治算法专题(一)——快速排序之【三路划分】

目录 1、分治算法简介 2、算法应用【leetcode】 2.1 题一&#xff1a;颜色分类 2.1.1 算法原理 2.2.1 算法代码 2.2 题二&#xff1a;排序数组——数组分三块原理 2.2.1 算法原理 2.2.2 算法代码 2.3 题三&#xff1a;数组中的第K个最大元素 2.3.1 算法原理 2.3.2 算…

各大平台统遭入侵??区块链市场遭攻击损失近3亿!

今年&#xff0c;全球发生多起骇人听闻的勒索入侵软件攻击事件&#xff0c;黑客组织利用各种手段和技术&#xff0c;不断试图突破网络安全防线&#xff0c;窃取敏感信息、破坏系统运行&#xff0c;甚至进行勒索和敲诈&#xff0c;使得网络安全问题日益凸显其重要性和紧迫性。 S…

Mysql分组取最新一条记录

文章目录 Mysql分组取最新一条记录1. 数据准备1. 方法1&#xff1a;使用子查询获取每个组的最大时间戳&#xff0c;然后再次查询获取具体记录&#xff08;如果时间戳是唯一的&#xff09;2. 方法2&#xff1a;使用窗口函数&#xff08;MySQL 8.0&#xff09;3. 方法3&#xff1…

TikTok跨境电商营销新策略:品牌联盟与影响力经济的结合

随着TikTok成为全球化的社交和电商平台&#xff0c;也给跨境卖家提供了新的商机。境电商通过与其他知名品牌、网红或KOC建立品牌联盟&#xff0c;能够有效实现资源共享、优势互补&#xff0c;并推动市场扩张&#xff0c;带来更大的商业价值和品牌影响力。本文Nox聚星将和大家探…

鸿蒙开发协调布局CollapsibleLayout

鸿蒙开发协调布局CollapsibleLayout 首先鸿蒙我暂时没找到官方提供的协调布局&#xff0c;所以得自己自定义。 一、思路 可滚动头部、粘性头部、可滚动内容布局 可折叠区域高度可滚动头部高度-粘性头部高度 二、效果图 鸿蒙开发协调布局CollapsibleLayout 三、关键代码 //…

优思学院|如何从零开始自己学习六西格玛?

优思学院为学习六西格玛管理的学员&#xff0c;精心推荐了几本由浅入深、系统全面的书籍&#xff0c;帮助大家从入门到精通&#xff0c;逐步掌握六西格玛这一强大的管理工具。无论你是刚接触六西格玛的初学者&#xff0c;还是想在专业领域提升的高级学员&#xff0c;这几本书都…

【ARM】Trustzone和安全架构

Trustzone的基本概念&背景和历史 什么是Trustzone&#xff1f; 什么是TEE&#xff1f; Trustzone是一个技术&#xff0c;是一个技术的设计&#xff0c;一个安全架构&#xff0c;既不是软件也不是硬件。 TEE (Trusted Execution Environment) 可信执行环境。就是依托Trust…

速响低代码平台:升级营销管理系统,开启高效无忧新体验!

当前日新月异的商业环境&#xff0c;企业面临着前所未有的挑战与机遇。随着市场竞争的日益加剧和企业业务的不断拓展&#xff0c;传统的营销方式和管理手段逐渐显露出其局限性&#xff0c;难以适应快速变化的市场需求。 数据收集难&#xff1a;传统的营销管理缺乏对客户数据的收…

战神诸神黄昏9月19日登录PC端! 手机怎么玩战神诸神黄昏

9月19日&#xff0c;《战神&#xff1a;诸神黄昏》正式登录PC端&#xff0c;这是一部动作冒险游戏。要是你想随时随地在手机或平板上也能玩《战神&#xff1a;诸神黄昏》&#xff0c;可以使用网易GameViewer远程帮你实现。 网易GameViewer远程作为一款专为游戏玩家打造的远程软…