C++基础之: 迭代器

简介

迭代器是 C++ 的一个重要组成部分, 它在数据结构和算法之间架起了桥梁. 迭代器作为通用指针, 可以遍历和操作容器中的元素, 同时隐藏底层的复杂性. 让我们一起探索现代 C++ 中迭代器的概念, 类别和使用场景.


什么是迭代器?

迭代器是一种抽象工具, 它允许顺序访问集合中的元素, 而无需暴露集合的底层实现. 迭代器是指针的泛化, 使得可以遍历数组, 向量, 列表等容器.

示例:

std::vector<int> vec{10, 20, 30, 40};
for (auto it = vec.begin(); it != vec.end(); ++it) {std::cout << *it << " ";
}
// 输出: 10 20 30 40

相比较而言, 传统的访问方式为:

for (size_t i = 0; i < vec.size(); i++) {std::cout << vec[i] << " ";
}
std::cout << std::endl;auto p = vec.data();
for (size_t i = 0; i < vec.size(); i++) {std::cout << p[i] << " ";
}
std::cout << std::endl;

迭代器类别

C++ 定义了多个迭代器类别, 每种类别具备不同的能力.

  1. 随机访问迭代器(Random Access Iterators): 支持完全的随机访问, 比较和算术操作.

    • 容器: std::vector, std::array, 原生数组.
    • 操作: ++, --, +=, -=, *, [], <, <=, >, >=
    #include <iostream>
    #include <vector>int main() {std::vector<int> vec{0, 1, 2, 3, 4, 5, 6, 7, 8};auto it = vec.begin();it++;it += 3;std::cout << *it << std::endl;    // 4std::cout << it[0] << std::endl;  // 4auto it2 = vec.begin() + 6;std::cout << std::boolalpha << (it < it2) << std::endl;  // true
    }
    
  2. 双向迭代器(Bidirectional Iterators): 支持向前和向后遍历.

    • 容器: 链表(std::list), 关联容器如 std::set, std::map.
    • 操作: ++, --, *, ==, !=
    #include <iostream>
    #include <list>int main() {std::list<int> vec{0, 1, 2, 3, 4, 5, 6, 7, 8};auto it = vec.begin();it++;std::cout << *it << std::endl;  // 1it--;std::cout << *it << std::endl;  // 0
    }
    
  3. 前向迭代器(Forward Iterators): 仅支持单向遍历.

    • 容器: std::forward_list, 无序关联容器 std::unordered_map, std::unordered_set
    • 操作: ++, *, ==, !=
    #include <iostream>
    #include <unordered_map>int main() {std::unordered_map<int, int> map{{1, 2}, {3, 4}, {5, 6}};auto it = map.begin();it++;//   it--; // Errorstd::cout << it->first << ": " << it->second << std::endl;  // 3: 4
    }
    
  4. 输入迭代器(Input Iterators): 设计用于一次性读取.

    • 示例: std::istream_iterator
  5. 输出迭代器(Output Iterators): 用于一次性写入到范围.

    • 示例: std::ostream_iterator

半开区间和安全性

迭代器遵循半开区间约定, 范围从 begin() 开始, 到 end() 前结束. 这种设计防止了越界访问.

示例:

std::vector<int> nums{1, 2, 3, 4};
for (auto it = nums.begin(); it != nums.end(); ++it) {std::cout << *it << " ";
}

STL 算法中的迭代器

标准模板库(STL)的算法利用迭代器实现与容器无关的操作. 例如:

  1. 查找元素:

    auto it = std::find(vec.begin(), vec.end(), value);
    if (it != vec.end()) {std::cout << "找到: " << *it;
    }
    
  2. 转换元素:

    std::transform(src.begin(), src.end(), dest.begin(), [](int x) { return x * x; });
    

需要避免的陷阱

  • 悬空迭代器: 修改容器(如调整大小或添加元素)可能会使现有的迭代器失效.
  • 迭代器不匹配: 比较来自不同容器的迭代器会导致未定义行为.

未定义行为示例:

  1. 在获取迭代器之后修改容器元素.

    std::vector<int> vec{1, 2, 3};
    auto it = vec.begin();
    vec.push_back(4);
    std::cout << *it; // 未定义行为: 迭代器失效
    
  2. 在遍历容器的时候删除迭代器

    void remove(std::vector<int>& vec, int target) {for (auto it = vec.begin(); it != vec.end(); it++) {if (*it == target) {vec.erase(it);}}
    }
    

现代增强

  1. 基于范围的循环(C++11), 使用 for 循环简化迭代:

    for (const auto& elem : vec) {std::cout << elem << " ";
    }
    
  2. 视图与过滤器(C++20), 引入对范围的惰性评估.

    auto filtered = vec | std::views::filter([](int x) { return x > 10; });
    for (int val : filtered) {std::cout << val << " ";
    }
    

总结

C++ 迭代器在数据结构和算法之间起着关键作用, 提供了灵活性和强大功能. 理解它们的类别, 正确用法和可能的陷阱, 可以确保高效且无错误的编程. 拥抱现代增强特性, 简化并优化您的代码!

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

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

相关文章

计算机的错误计算(二百一十二)

摘要 利用两个大模型计算 实验表明&#xff0c;两个大模型均进行了中肯的分析。另外&#xff0c;其中一个大模型给出了 Python代码&#xff0c;运行后&#xff0c;结果中有7位错误数字&#xff1b;而一个大模型进行加减运算时出错。 例1. 计算 下面是与一个大模型的对话…

Vue+Echarts+百度地图 实现 路径规划

实现功能: 通过选择 相关调拨&#xff0c;系统自动规划 路径&#xff0c;并且以地图的形式呈现最佳路径 技术难点: 1. vue 结合使用 echarts 2.echarts 在 vue嵌入百度地图&#xff0c;并且做出路径 曲线 最终结果:

【算法】图解两个链表相交的一系列问题

问&#xff1a; 给定两个可能有环也可能无环的单链表&#xff0c;头节点head1和head2。请实现一个函数&#xff0c;如果两个链表相交&#xff0c;请返回相交的第一个节点&#xff1b;如果不相交&#xff0c;返回null。如果两个链表长度之和为N&#xff0c;时间复杂度请达到O(N…

Go-Zero整合Goose实现MySQL数据库版本管理

推荐阅读 【系列好文】go-zero从入门到精通&#xff08;看了就会&#xff09; 教程地址&#xff1a;https://blog.csdn.net/u011019141/article/details/139619172 Go-Zero整合Goose实现MySQL数据库版本管理的教程 在开发中&#xff0c;数据库迁移和版本管理是必不可少的工作。…

JAVA:Spring Boot 集成 JWT 实现身份验证的技术指南

1、简述 在现代Web开发中&#xff0c;安全性尤为重要。为了确保用户的身份&#xff0c;JSON Web Token&#xff08;JWT&#xff09;作为一种轻量级且无状态的身份验证方案&#xff0c;广泛应用于微服务和分布式系统中。本篇博客将讲解如何在Spring Boot 中集成JWT实现身份验证…

说一说mongodb组合索引的匹配规则

一、背景 有一张1000多万条记录的大表&#xff0c;需要做归档至历史表&#xff0c;出现了大量慢查询。 查询条件是 "classroomId": {$in: ["xxx", "xxx", ..... "xxx","xxx", "xxx" ] }耗时近5秒&#xff0c;且…

更新java

下载 Java 下载 |神谕 (oracle.com)

CSS3的aria-hidden学习

前言 aria-hidden 属性可用于隐藏非交互内容&#xff0c;使其在无障碍 API 中不可见。即当aria-hidden"true" 添加到一个元素会将该元素及其所有子元素从无障碍树中移除&#xff0c;这可以通过隐藏来改善辅助技术用户的体验&#xff1a; 纯装饰性内容&#xff0c;如…

【Java设计模式-5】装饰模式:给咖啡加点“佐料”

今天咱们要探索一下Java世界里的装饰模式&#xff08;Decorator Pattern&#xff09;。为了让这个过程更加生动易懂&#xff0c;咱们就以大家都熟悉的咖啡饮品来举例吧&#xff0c;想象一下&#xff0c;你就是那个咖啡大师&#xff0c;要给顾客调制出各种独特口味的咖啡哦&…

C++(5)

1.运算符重载 头文件 #ifndef MYSTRING_H #define MYSTRING_H#include <iostream> #include <cstring>using namespace std;class myString { private:char *str;//C风格字符串int size0; public:std::string s_str;//转换构造函数myString(const std::string &a…

K8S--配置存活、就绪和启动探针

目录 1 本人基础环境2 目的3 存活、就绪和启动探针介绍3.1 存活探针3.2 就绪探针3.3 启动探针 4 探针使用场景4.1 存活探针4.2 就绪探针4.3 启动探针 5 配置存活、就绪和启动探针5.1 定义存活探针5.2 定义一个存活态 HTTP 请求接口5.3 定义 TCP 的就绪探针、存活探测5.4 定义 g…

【HTML+CSS+JS+VUE】web前端教程-36-JavaScript简介

JavaScript介绍 JavaScript是一种轻量级的脚本语言&#xff0c;所谓脚本语言&#xff0c;指的是它不具备开发操作系统的能力&#xff0c;而是用来编写控制其他大型应用程序的“脚本” JavaScript是一种嵌入式语言&#xff0c;它本身提供的核心语法不算很多 为什么学习JavaScri…

LLM实现视频切片合成 前沿知识调研

1.相关产品 产品链接腾讯智影https://zenvideo.qq.com/可灵https://klingai.kuaishou.com/即梦https://jimeng.jianying.com/ai-tool/home/Runwayhttps://aitools.dedao.cn/ai/runwayml-com/Descripthttps://www.descript.com/?utm_sourceai-bot.cn/Opus Cliphttps://www.opu…

AI多模态论文解读:LLaVA-CoT:让视觉语言模型逐步推理

本文作者&#xff1a;AIGCmagic社区 猫先生 一、简 介 LLaVA-CoT引入了四个不同的阶段&#xff08;摘要、标题、推理和结论&#xff09;&#xff0c;使模型能够独立进行系统化的多阶段推理&#xff0c;显著提高了在推理密集型任务上的准确性。 编译了LLaVA-CoT-100k数据集&am…

分布式缓存redis

分布式缓存redis 1 redis单机&#xff08;单节点&#xff09;部署缺点 &#xff08;1&#xff09;数据丢失问题&#xff1a;redis是内存存储&#xff0c;服务重启可能会丢失数据 &#xff08;2&#xff09;并发能力问题&#xff1a;redis单节点&#xff08;单机&#xff09;部…

《C++11》nullptr介绍:从NULL说起

在C11之前&#xff0c;我们通常使用NULL来表示空指针。然而&#xff0c;NULL在C中有一些问题和限制&#xff0c;这就是C11引入nullptr的原因。本文将详细介绍nullptr的定义、用法和优点。 1. NULL的问题 在C中&#xff0c;NULL实际上是一个整数0&#xff0c;而不是一个真正的…

供应链数字化转型参考大型供应链系统技术架构设计方案

该文介绍了一个大型供应链系统技术架构的设计方案&#xff0c;包括整体设计、核心技术目录和应用案例。设计采用Choerodon微服务框架&#xff0c;关注海量并发、可伸缩性、安全性等方面。同时&#xff0c;方案符合大型企业结构的HR组织架构&#xff0c;支持多级组织架构和角色、…

STM32F1学习——DMA直接存储器存取

一、DMA直接存储器存取 DMA的全称是 Direct Memory Access 直接存储器存取&#xff0c;他可以提供外设和存储器间或存储器和存储器间的高速数据传输&#xff0c;无需CPU的干预。 STM32有12个DMA通道&#xff0c;由DMA1(7个通道组成)和DMA2(5个通道组成)&#xff0c;STM32F103C8…

一个使用 Golang 编写的新一代网络爬虫框架,支持JS动态内容爬取

大家好&#xff0c;今天给大家分享一个由ProjectDiscovery组织开发的开源“下一代爬虫框架”Katana&#xff0c;旨在提供高效、灵活且功能丰富的网络爬取体验&#xff0c;适用于各种自动化管道和数据收集任务。 项目介绍 Katana 是 ProjectDiscovery 精心打造的命令行界面&…

6.2 MySQL时间和日期函数

以前我们就用过now()函数来获得系统时间&#xff0c;用datediff()函数来计算日期相差的天数。我们在计算工龄的时候&#xff0c;让两个日期相减。那么其中的这个now函数返回的就是当前的系统日期和时间。 1. 获取系统时间函数 now()函数&#xff0c;返回的这个日期和时间的格…