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,一经查实,立即删除!

相关文章

C++并发编程之std::partial_sum的并行版本

在C中&#xff0c;std::partial_sum 是一个用于计算前缀和的算法&#xff0c;它将输入范围中的每个元素替换为其前缀和。为了提高性能&#xff0c;我们可以设计并实现一个并行版本的 std::partial_sum&#xff0c;以便在多核处理器上并行执行前缀和计算。基本思想是将输入范围划…

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

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

常见的php框架有哪几个?

一直以来&#xff0c;PHP作为一种广泛使用的编程语言&#xff0c;拥有着许多优秀的框架来帮助开发人员快速构建稳定的Web应用程序。本文降为大家介绍几种常见的PHP的主流框架&#xff0c;以及它们相关的特点和使用场景。如有问题&#xff0c;欢迎指正&#xff01; 1.Laravel&a…

zerotier已配置但ip连不上?

利用zerotier内网渗透&#xff0c;在公网上远程连接使用局域网内的服务器&#xff0c;经常遇到连接不上的问题 zerotier配置过程 解决方法 声明&#xff1a;个人使用过程中&#xff0c;发现的有效解决方法&#xff0c;不一定能解决所有人的问题 总结&#xff1a; 重启Zerotier…

GORM(Go语言数据交互库)

GORM&#xff08;Go ORM&#xff0c;即对象关系映射&#xff09;是Go语言中非常流行且功能强大的数据库交互库。它简化了与关系型数据库的交互过程&#xff0c;提供了丰富的API来处理各种数据库操作。下面将详细介绍GORM的功能、使用方法和一些高级特性。 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…

Elasticsearch实战指南:从入门到高效使用

Elasticsearch实战指南&#xff1a;从入门到高效使用 1. 引言&#xff1a;Elasticsearch是什么&#xff1f; Elasticsearch是一个分布式、RESTful风格的搜索和分析引擎&#xff0c;广泛应用于全文搜索、日志分析、实时数据分析等场景。它的核心特点包括&#xff1a; 高性能&…

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实现身份验证…

【AI学习】地平线首席架构师苏箐关于自动驾驶的演讲

在地平线智驾科技畅想日上&#xff0c;地平线副总裁兼首席架构师苏箐&#xff08;前华为智驾负责人&#xff09;做了即兴演讲&#xff0c;以下是其演讲的主要内容&#xff1a; 对自动驾驶行业的看法 自动驾驶的难度与挑战&#xff1a;苏箐表示自动驾驶非常难&#xff0c;他做自…

说一说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;如…

LeetCode 3066.超过阈值的最少操作数 II:模拟 - 原地建堆O(1)空间 / 优先队列O(n)空间

【LetMeFly】3066.超过阈值的最少操作数 II&#xff1a;模拟 - 原地建堆O(1)空间 / 优先队列O(n)空间 力扣题目链接&#xff1a;https://leetcode.cn/problems/minimum-operations-to-exceed-threshold-value-ii/ 给你一个下标从 0 开始的整数数组 nums 和一个整数 k 。 一次…

C# 下 SQLite 并发操作与锁库问题的 5 种解决方案

开篇&#xff1a;你是否被 SQLite 并发锁库困扰&#xff1f; 在当今数字化的时代浪潮中&#xff0c;数据已然成为了企业与开发者们手中最为宝贵的资产之一。C# 作为一门广泛应用于各类软件开发的强大编程语言&#xff0c;常常需要与数据库进行紧密交互&#xff0c;以实现数据的…

如何安装cnpm

今天尝试用npm install安装一个项目的依赖&#xff0c;但是无论如何都不能完成&#xff0c;等待时间非常久&#xff0c;所以同事推荐了cnpm&#xff0c;确实非常好用&#xff0c;所以推荐了出来&#xff0c;希望能给大家带来帮助。 cnpm 是中国淘宝团队提供的一个 npm 镜像工具…

【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…