C++初学者指南-5.标准库(第一部分)--容器遍历

C++初学者指南-5.标准库(第一部分)–容器遍历

文章目录

  • C++初学者指南-5.标准库(第一部分)--容器遍历
    • 前向遍历
      • 基于范围的循环
      • for_each / for_each_n
      • 迭代器的显式使用
      • 基于索引的循环
    • 逆向遍历
      • 反向范围循环(C++20)
      • 反向 for_each / for_each_n
      • 反向迭代器的显式使用
      • 基于索引的反向循环
    • 工具
      • 获取下一个/上一个迭代器
    • 相关内容

  • 尝试只在你想做的事情没有经过良好测试的(标准)库函数/算法的情况下编写循环!
  • 对于像std::vector这样的序列容器,首选非随机线性前向遍历,这得益于对缓存和预取的友好性
  • 只有一些标准容器支持反向遍历

前向遍历

基于范围的循环

for (type variable : container)

  • 适用于所有标准序列和关联式容器
  • 与容器无关⇒易于更改容器类型
  • 没有可能发生越界访问错误
  • 无需担心有符号/无符号的索引类型问题
  • 由于线性存取模式,使用序列容器时性能最佳 (缓存和预取友好)
  • 可以用break实现早期退出;
  • 不适合需要随机访问模式的算法
std::vector<Type> v {};
// 只读,类型的复制成本较低或者需要复制:
for (Type x : v) { cout << x; }
for (auto x : v) { cout << x; }
// 只读,类型复制的成本很高时:
for (Type const& x : v) { cout << x; }
for (auto const& x : v) { cout << x; }
// 修改值时:
for (Type& x : v) { cin >> x; }
for (auto& x : v) { cin >> x; }

for_each / for_each_n

  • 如果你已经有一个可以应用于每个元素的函数(对象),那会比较方便。
  • 适用于所有标准序列和关联容器。
  • 与容器无关⇒易于更改容器类型。
  • 无需担心有符号/无符号索引类型的麻烦。
  • 自说明性名称。
  • 使用迭代器范围可能存在越界访问错误。

在这里插入图片描述
不可能发生越界访问
cppreference

#include <algorithm>  // std::ranges::for_each
namespace ranges = std::ranges;  // alias
Container<Type> v;// 只读,类型的复制成本较低或者需要复制:
ranges::for_each(v, [](Type x){ cout << x; }); 
ranges::for_each(v, [](auto x){ cout << x; });
// 只读,类型复制的成本很高时:
ranges::for_each(v, [](Type const& x){ cout << x; });
ranges::for_each(v, [](auto const& x){ cout << x; });
// 修改值时:
ranges::for_each(v, [](Type& x){ cin >> x; });
ranges::for_each(v, [](auto& x){ cin >> x; });

在这里插入图片描述

  • 可用于子范围
  • 可能存在越界访问漏洞
    cppreference
#include <algorithm>  // std::for_each
Container<Type> v;// 只读,类型的复制成本较低或者需要复制:
for_each(begin(v), end(v),       [](Type x){ cout << x; });
for_each(begin(v)+2, begin(v)+5, [](auto x){ cout << x; });
// 只读,类型复制的成本很高时:
for_each(begin(v), end(v), [](Type const& x){ cout << x; });
for_each(begin(v), end(v), [](auto const& x){ cout << x; });
//修改值时:
for_each(begin(v), end(v), [](Type& x){ cin >> x; });
for_each(begin(v), end(v), [](auto& x){ cin >> x; });

在这里插入图片描述

  • 可用于子范围
  • 可能存在越界访问漏洞

迭代器的显式使用

  • 不受容器限制 ⇒ 容器类型易更改
  • 适用于所有标准序列容器
  • 无需担心有符号/无符号索引类型的麻烦
  • 可以跳过多个元素
  • 可能存在越界访问错误
  • 繁琐
std::vector<int> v {1, 2, 3, 4, 5, 6};
for (auto i = begin(v); i != end(v); ++i) { cout << *i; }
for (auto i = begin(v); i != end(v); ++i) { cin  >> *i; }
// 只读,使用常量迭代器
for (auto i = cbegin(v); i != cend(v); ++i { cout << *i; }

基于索引的循环

  • 可以跳过多个元素
  • 易受越界访问错误困扰
  • 由于有符号/无符号索引类型转换,很容易出现难以察觉的bug
  • 不适用于所有序列容器 ⇒ 不容易更改容器类型
  • 确保循环不修改元素需要更多的约束
  • 繁琐
std::vector<int> v {1, 2, 3, 4, 5, 6};
for (std::size_t i = 0; i < v.size(); ++i) { cout << v[i]; }
// 显式只读
const auto& cv = v;
for (std::size_t i = 0; i < cv.size(); ++i) { cout << cv[i]; }

逆向遍历

反向范围循环(C++20)

for (type variable : container | std::views::reverse)

  • 适用于所有双向容器
  • 不会出现越界访问错误
  • 不需要担心有符号/无符号索引类型的麻烦
  • 可以通过 break 实现提前退出
#include <ranges> //C++20
std::vector<int> v {1, 2, 3, 4, 5, 6};
for (int x : v | std::views::reverse) { cout << x << '\n'; }
// 只读,类型的复制成本较低或者需要复制:
for (auto x : v | std::views::reverse) { cout << x; }
// 只读,类型复制的成本很高时:
for (auto const& x : v | std::views::reverse) { cout << x; }
// 修改值时:
for (auto& x : v | std::views::reverse) { cin >> x; }

反向 for_each / for_each_n

  • 如果你已经有一个可以应用到每个元素的函数(对象),那是非常方便的
  • 适用于所有双向容器
  • 容易更改容器类型
  • 没有有符号/无符号索引类型的麻烦
  • 有界限迭代器访问的错误可能会发生
  • 具有自我说明的名称
    在这里插入图片描述
    不会发生越界访问
    cppreference
#include <algorithm>  // std::ranges::for_each
#include <ranges>     // range views
namespace ranges = std::ranges;        // alias
namespace views = std::ranges::views;  // alias
Container<Type> v;// 只读,类型的复制成本较低或者需要复制:
ranges::for_each(views::reverse(v), [](Type x){ cout << x; }); 
ranges::for_each(views::reverse(v), [](auto x){ cout << x; });
// 只读,类型复制的成本很高时:
ranges::for_each(views::reverse(v), [](Type const& x){ cout << x; });
ranges::for_each(views::reverse(v), [](auto const& x){ cout << x; });
// 修改值时:
ranges::for_each(views::reverse(v), [](Type& x){ cin >> x; });
ranges::for_each(views::reverse(v), [](auto& x){ cin >> x; });

在这里插入图片描述

  • 可用于子范围
  • 可能存在越界访问漏洞
    cppreference
#include <algorithm>  // std::for_each
Container<Type> v;// 只读,类型的复制成本较低或者需要复制:
for_each(rbegin(v), rend(v),       [](Type x){ cout << x; });
for_each(rbegin(v)+2, rbegin(v)+5, [](auto x){ cout << x; });
// 只读,类型复制的成本很高时:
for_each(rbegin(v), rend(v), [](Type const& x){ cout << x; });
for_each(rbegin(v), rend(v), [](auto const& x){ cout << x; });
// 修改值时:
for_each(rbegin(v), rend(v), [](Type& x){ cin >> x; });
for_each(rbegin(v), rend(v), [](auto& x){ cin >> x; });

在这里插入图片描述

  • 可用于子范围
  • 可能存在越界访问漏洞

反向迭代器的显式使用

  • 适用于所有双向容器
  • 无需担心有符号/无符号索引类型问题
  • 可以跳过多个元素
  • 可能出现越界访问错误
  • 繁琐
std::vector<int> v {1, 2, 3, 4, 5, 6};
for (auto i = rbegin(v); i != rend(v); ++i) { cout << *i; }
for (auto i = rbegin(v); i != rend(v); ++i) { cin  >> *i; }
// 只读,使用常量迭代器
for (auto i = crbegin(v); i != crend(v); ++i { cout << *i; }

基于索引的反向循环

  • 容易出现越界访问漏洞
  • 由于无符号大小类型而出现微妙错误容易编写:隐式转换为有符号整数,溢出/反转,…
  • 确保循环不修改元素需要更多约束
  • 繁琐
std::vector<int> v {1, 2, 3, 4, 5, 6};
// 标准容器使用无符号size类型
// ⇒ 注意不要减少无符号“0”
for (auto i = v.size(); i > 0; --i) { cout << v[i-1]; }
// 显式只读
const auto& cv = v;
for (auto i = cv.size(); i > 0; --i) { cout << cv[i-1]; }

工具

获取下一个/上一个迭代器

#include <iterator>
函数 std::prev 和 std::next 提供了一种通用的方式来递增/递减迭代器,即使迭代器类型不支持随机访问(例如,it += 5)。
然而,请注意,通过N步前进非随机访问迭代器(例如std::list中的迭代器)可能成本会很高,即涉及大约N个内存操作。

在这里插入图片描述
cppreference
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

相关内容

std::vector
标准库顺序容器
标准库关联容器
A Tour of C++: Containers and Algorithms

附上原文链接
如果文章对您有用,请随手点个赞,谢谢!^_^

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

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

相关文章

本地部署,APISR: 动漫超分辨率技术

目录 引言 技术背景 APISR 的架构与原理 APISR 的主要特点 应用实例 本地部署 运行结果 结论 参考文献 GitHub - Kiteretsu77/APISR: APISR: Anime Production Inspired Real-World Anime Super-Resolution (CVPR 2024)APISR: Anime Production Inspired Real-World A…

Why can‘t I access GPT-4 models via API, although GPT-3.5 models work?

题意&#xff1a;为什么我无法通过API访问GPT-4模型&#xff0c;尽管GPT-3.5模型可以工作&#xff1f; 问题背景&#xff1a; Im able to use the gpt-3.5-turbo-0301 model to access the ChatGPT API, but not any of the gpt-4 models. Here is the code I am using to tes…

vue仿甘特图开发工程施工进度表

前言 本文是根据项目实际开发中一个需求开发的demo&#xff0c;仅用了elementUI&#xff0c;可当作独立组件使用&#xff0c;C V即用。 当然没考虑其他的扩展性和一些数据的校验&#xff0c;主要是提供一个处理思路&#xff0c;有需要的小伙伴可以直接复制&#xff1b;本demo的…

元服务体验-服务发现

服务发现&#xff0c;无论线上或线下的方式都可以发现元服务。 线上&#xff1a;基于用户意图。从精准意图的搜索、用户事件触发的推荐到主动探索等场景。用户可以在设备的负一屏、全局搜索、应用市场、桌面等场景发现元服务。 线下&#xff1a;用户在 HarmonyOS Connect标签…

C++ | Leetcode C++题解之第238题除自身以外数组的乘积

题目&#xff1a; 题解&#xff1a; class Solution { public:vector<int> productExceptSelf(vector<int>& nums) {int length nums.size();// L 和 R 分别表示左右两侧的乘积列表vector<int> L(length, 0), R(length, 0);vector<int> answer(l…

Modbus转Ethernet/IP网关模块与汇川PLC通讯案例

Modbus转Ethernet/IP网关模块&#xff08;XD-MDEP100&#xff09;是一种用于将Modbus协议转换为Ethernet/IP协议的设备。它可以将Modbus RTU和Modbus TCP两种不同格式的Modbus数据包转换为Ethernet/IP协议的数据包&#xff0c;实现不同厂家的设备之间的数据交换和共享。在汇川P…

解决elementUI列表的疑难杂症,排序显示错乱的问题

大家好&#xff0c;在使用elementUI表格时&#xff0c;有时会出现一些意料之外的问题&#xff0c;比如数据排序正常但表格显示、排序错乱等。在网上搜索后一般有2种解决方法&#xff1a;1.给表格每一项的el-table-column添加唯一的id用于区分。2.给表格每一项的el-table-column…

案例 | 人大金仓助力山西政务服务核心业务系统实现全栈国产化升级改造

近日&#xff0c;人大金仓支撑山西涉企政策服务平台、政务服务热线联动平台、政务网、办件中心等近30个政务核心系统完成全栈国产化升级改造&#xff0c;推进全省通办、跨省通办、综合业务受理、智能审批、一件事一次办等业务的数字化办结进程&#xff0c;为我国数字政务服务提…

mybatis语法进阶1

日志的使用 我们在使用MyBatis的时候, 其实MyBatis框架会打印一些必要的日志信息, 在开发阶段这些日志信息对我们分析问题,理解代码的执行是特别有帮助的; 包括项目上线之后,我们也可以收集项目的错误日志到文件里面去; 所以我们采用专门的日志系统来处理. 步骤 导入坐标拷贝…

如何在SpringCloud中使用Kafka Streams实现实时数据处理

使用Kafka Streams在Spring Cloud中实现实时数据处理可以帮助我们构建可扩展、高性能的实时数据处理应用。Kafka Streams是一个基于Kafka的流处理库&#xff0c;它可以用来处理流式数据&#xff0c;进行流式计算和转换操作。 下面将介绍如何在Spring Cloud中使用Kafka Streams实…

pytorch说明

深度学习中的重要概念&#xff1a; 激活函数&#xff1a; 激活函数的必要性&#xff1a;激活函数不是绝对必须的&#xff0c;但在深度学习中&#xff0c;它们几乎总是被使用。激活函数可以引入非线性&#xff0c;这使得神经网络能够学习更复杂的模式。 激活函数的位置&#x…

记录些MySQL题集(9)

MySQL之死锁问题分析、事务隔离与锁机制的底层原理剖析 一、MySQL中的死锁现象 所谓的并发事务&#xff0c;本质上就是MySQL内部多条工作线程并行执行的情况&#xff0c;也正由于MySQL是多线程应用&#xff0c;所以需要具备完善的锁机制来避免线程不安全问题的问题产生&#…

嵌入式智能手表项目实现分享

简介 这是一个基于STM32F411CUE6和FreeRTOS和LVGL的低成本的超多功能的STM32智能手表~ 推荐 如果觉得这个手表的硬件难做,又想学习相关的东西,可以试下这个新出的开发板,功能和例程demo更多!FriPi炸鸡派STM32F411开发板: 【STM32开发板】 FryPi炸鸡派 - 嘉立创EDA开源硬件平…

STM32入门开发操作记录(二)——LED与蜂鸣器

目录 一、工程模板二、点亮主板1. 配置寄存器2. 调用库函数 三、LED1. 闪烁2. 流水灯 四、蜂鸣器 一、工程模板 参照第一篇&#xff0c;新建工程目录ProjectMould&#xff0c;将先前打包好的Start&#xff0c;Library和User文件^C^V过来&#xff0c;并在Keil5内完成器件支持包的…

【ARM】CCI集成指导整理

目录 1.CCI集成流程 2.CCI功能集成指导 2.1CCI结构框图解释 Request concentrator Transaction tracker Read-data Network Write-data Network B-response Network 2.2 接口注意项 记录一下CCI500的ACE slave interface不支持的功能&#xff1a; 对于ACE-Lite slav…

手机和电脑通过TCP传输(一)

一.工具 手机端&#xff1a;网络调试精灵 电脑端&#xff1a;野火网络调试助手 在开始通信之前&#xff0c;千万要查看一下电脑的防火墙是否关闭&#xff0c;否则可能会无法通信 在开始通信之前&#xff0c;千万要查看一下电脑的防火墙是否关闭&#xff0c;否则可能会无法通信…

vue3+TS从0到1手撸后台管理系统

1.路由配置 1.1路由组件的雏形 src\views\home\index.vue&#xff08;以home组件为例&#xff09; 1.2路由配置 1.2.1路由index文件 src\router\index.ts //通过vue-router插件实现模板路由配置 import { createRouter, createWebHashHistory } from vue-router import …

【学习笔记】无人机系统(UAS)的连接、识别和跟踪(一)-3GPP TS 23.256 技术规范概述

3GPP TS 23.256 技术规范&#xff0c;主要定义了3GPP系统对无人机&#xff08;UAV&#xff09;的连接性、身份识别、跟踪及A2X&#xff08;Aircraft-to-Everything&#xff09;服务的支持。 3GPP TS 23.256 技术规范&#xff1a; 以下是文档的核心内容总结&#xff1a; UAV系…

类和对象的简述(c++篇)

开局之前&#xff0c;先来个小插曲&#xff0c;放松一下&#xff1a; 让我们的熊二来消灭所有bug 各位&#xff0c;在这祝我们&#xff1a; 放松过后&#xff0c;开始步入正轨吧。爱学习的铁子们&#xff1a; 目录&#xff1a; 一类的定义&#xff1a; 1.简述&#xff1a; 2…

【Springboot】新增profile环境配置应用启动失败

RT 最近接手了一个新的项目&#xff0c;为了不污染别人的环境&#xff0c;我新增了一个自己的环境配置。结果&#xff0c;在启动的时候总是失败&#xff0c;就算是反复mvn clean install也是无效。 问题现象 卡住无法进行下一步 解决思路 由于之前都是能启动的&#xff0c…