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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

提高自动化测试脚本编写效率 5大关键注意事项

提高自动化测试脚本编写效率能加速测试周期&#xff0c;减少人工错误&#xff0c;提升软件质量&#xff0c;促进项目按时交付&#xff0c;增强团队生产力和项目成功率。而自动化测试脚本编写效率低下&#xff0c;往往会导致测试周期延长&#xff0c;增加项目成本&#xff0c;延…

搞定锁存器和触发器(SR、D、T、JK)

搞定锁存器和触发器&#xff08;SR、D、T、JK&#xff09; 文章目录 搞定锁存器和触发器&#xff08;SR、D、T、JK&#xff09;开胃小菜——基本双稳态电路锁存器1、SR锁存器1.1 或非门SR锁存器S 0 &#xff0c;R 1 (0状态)S 1 &#xff0c;R 0 (1状态)S R 0 (不起作用)S…

初识langchain[1]:Langchain实战教学,利用qwen2.1与GLM-4大模型构建智能解决方案[含Agent、tavily面向AI搜索]

初识langchain[1]&#xff1a;Langchain实战教学&#xff0c;利用qwen2.1与GLM-4大模型构建智能解决方案 1.大模型基础知识 大模型三大重点&#xff1a;算力、数据、算法&#xff0c;ReAct &#xff08;reason推理act行动&#xff09;–思维链 Langchain会把上述流程串起来&a…

<Rust>egui部件学习:如何在窗口及部件显示中文字符?

前言 本专栏是关于Rust的GUI库egui的部件讲解及应用实例分析&#xff0c;主要讲解egui的源代码、部件属性、如何应用。 环境配置 系统&#xff1a;windows 平台&#xff1a;visual studio code 语言&#xff1a;rust 库&#xff1a;egui、eframe 概述 本文是本专栏的第一篇博…

2024 睿抗机器人开发者大赛CAIP-编程技能赛-本科组(省赛)

RC-u1 热҈热҈热҈ 分数 10 全屏浏览 切换布局 作者 DAI, Longao 单位 杭州百腾教育科技有限公司 热҈热҈热҈……最近热得打的字都出汗了&#xff01; 幸好某连锁餐厅开启了气温大于等于 35 度即可获得一杯免费雪碧的活动。但不知为何&#xff0c;在每个星期四的时候&#x…

javaWeb 增删改查基本操作

通过之前的文章可以快速的了解SpringBoot 项目&#xff0c;这是一个关于增删改查的案例&#xff0c;可以巩固之前学习到的知识。 案例开始 准备工作 需求 开发员工管理系统&#xff0c;提供增删改查功能。 环境搭建 数据库&#xff08;mysql&#xff09; emp、dept表导入 #…

目标检测入门:4.目标检测中的一阶段模型和两阶段模型

在前面几章里&#xff0c;都只做了目标检测中的目标定位任务&#xff0c;并未做目标分类任务。目标检测作为计算机视觉领域的核心人物之一&#xff0c;旨在从图像中识别出所有感兴趣的目标&#xff0c;并确定它们的类别和位置。现在目标检测以一阶段模型和两阶段模型为代表的。…

网络安全——防御课实验二

在实验一的基础上&#xff0c;完成7-11题 拓扑图 7、办公区设备可以通过电信链路和移动链路上网(多对多的NAT&#xff0c;并且需要保留一个公网IP不能用来转换) 首先&#xff0c;按照之前的操作&#xff0c;创建新的安全区&#xff08;电信和移动&#xff09;分别表示两个外网…

个人和企业之间该怎么选择合适的SSL证书?

选择合适的SSL证书对于维护网站的安全性和提升用户信任至关重要。个人和企业在选择SSL证书时&#xff0c;应考虑网站类型、安全需求、预算限制以及用户对网站的信任度等因素。以下是一些具体的建议&#xff1a; 个人用户&#xff1a; 类型建议&#xff1a;对于个人网站、博客或…

base SAS programming学习笔记13(Array)

1.Array array-name{dimension} <elements> array-name&#xff1a;向量名称 dimension&#xff1a;向量长度&#xff0c;默认为1&#xff1b; elements:列出变量名&#xff0c;变量名要么全是数值变量或者全是字符变量 array-name和variable不能相同&#xff1b;也不能和…

飞睿智能UWB Tag蓝牙防丢器标签,宠物安全新升级,5cm精准定位测距不迷路

宠物早已成为许多家庭不可或缺的一员&#xff0c;它们用无条件的爱温暖着我们的心房&#xff0c;陪伴我们度过每一个平凡而温馨的日子。然而&#xff0c;随着宠物活动范围的扩大和外界环境的复杂多变&#xff0c;宠物走失的风险也随之增加。每一次出门遛弯&#xff0c;都像是心…

【Git的基本操作】版本回退 | 撤销修改的三种情况 | 删除文件

目录 5.版本回退 5.1选项hard&后悔药 5.2后悔药&commit id 5.3版本回退的原理 6.撤销修改 6.1情况一 6.2情况二 6.3情况三 ​7.删除文件 Git重要能力之一马&#xff0c;版本回退功能。Git是版本控制系统&#xff0c;能够管理文件历史版本。本篇以ReadMe文件为…

【CSS in Depth 2 精译_018】3.1.2 逻辑属性 + 3.1.3 用好逻辑属性的简写形式

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第一章 层叠、优先级与继承&#xff08;已完结&#xff09; 1.1 层叠1.2 继承1.3 特殊值1.4 简写属性1.5 CSS 渐进式增强技术1.6 本章小结 第二章 相对单位&#xff08;已完结&#xff09; 2.1 相对…

Windows与Linux双机热备软件推荐

网络数据安全在如今信息化的时代越来越变得举足轻重&#xff0c;因此服务器维护和管理也成为企业健康稳定运营的一项重要工作。但实际情况是很多公司并没有配备专业的运维人员&#xff0c;一般都会通过一些管理软件维护或者主机托管给服务商。整理6款服务器的Windows与Linux双机…

django报错(三):No crontab program或got an unexpected keyword argument ‘user’

Crontab是linux系统上的定时管理模块&#xff0c;简单配置&#xff0c;灵活使用。但是要在windows使用必须借助Cygwin等虚拟工具&#xff0c;否则会报错“No crontab program”。如下图&#xff1a; python-crontab是其提供了python模块对crontab的访问&#xff0c;即可以通过p…

2024年公路水运工程施工企业安全生产管理人员证模拟考试题库及公路水运工程施工企业安全生产管理人员理论考试试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年公路水运工程施工企业安全生产管理人员证模拟考试题库及公路水运工程施工企业安全生产管理人员理论考试试题是由安全生产模拟考试一点通提供&#xff0c;公路水运工程施工企业安全生产管理人员证模拟考试题库是…

强化学习——多臂老虎机问题(MAB)【附python代码】

文章目录 一、问题描述1.1 问题定义1.2 形式化描述1.3 累积懊悔1.4 估计期望奖励 二、解决方法2.1 ϵ-贪婪算法2.2 上置信界算法2.3 汤普森采样算法2.4 小结 一、问题描述 1.1 问题定义 有一个用于 K 根拉杆的老虎机&#xff0c;每一根拉杆都对应一个关于奖励的概率分布 R 。每…

【JavaScript 算法】贪心算法:局部最优解的构建

&#x1f525; 个人主页&#xff1a;空白诗 文章目录 一、贪心算法的基本概念贪心算法的适用场景 二、经典问题及其 JavaScript 实现1. 零钱兑换问题2. 活动选择问题3. 分配问题 三、贪心算法的应用四、总结 贪心算法&#xff08;Greedy Algorithm&#xff09;是一种逐步构建解…

【前端6*】表格-表单2(弹窗在父组件)父子组件调用 vue element-ui

vue element-ui 中表单弹框的使用 写在最前面一、完整代码1、&#xff08;子组件&#xff09;E:\ui\参考代码\demo-new\src\components\detail.vue2、&#xff08;父组件&#xff09;E:\ui\参考代码\demo-new\src\views\Home.vue 二、小结 &#x1f308;你好呀&#xff01;我是…

Qt Style Sheets-入门

Qt 样式表是一种强大的机制&#xff0c;允许您自定义小部件的外观&#xff0c;这是在通过子类化QStyle已经可行的基础上的补充。Qt 样式表的概念、术语和语法在很大程度上受到 HTML级联样式表 (CSS)的启发&#xff0c;但适用于小部件的世界。 概述 样式表是文本规范&#xff0…