《Effective STL》读书笔记(四):迭代器

news2024/11/30 11:46:12

iterator 优先于 const_iterator, reverse_iterator, const_reverse_iterator

STL中所有标准容器都提供了标题提到的四种迭代器类型。对于容器container<T>而言,iterator类型相当于T*const_iterator类型相当于const T*,剩下两个是反向迭代器的普通类型和const类型。

对于vector<T>容器中的inserterase来说,inserterase的函数原型如下

iterator insert(iterator position, const T& x);
iterator erase(iterator position);
iterator erase(iterator rangeBegin, iterator rangeEnd);

每个标准容器都有类似的函数,只不过返回值类型可能有所不同。但是这些函数都只接收iterator类型的参数。

四种迭代器的关系如下图所示

image-20230907095819669

从图中看出,从iteratorconst_iterator,和从reverse_iteratorconst_reverse_iterator均可以通过隐式类型转换得到;而从reverse_iteratoriterator,和从const_reverse_iterator均可以通过调用base成员函数得到。

当在iteratorconst_iterator中选择时,优先选择iterator,不仅仅因为iterator可以用于更多的成员函数,还因为iteratorconst_iterator混用时会产生一些问题:

typedef deque<int> IntDeque;
typedef IntDeque::iterator Iter;
typedef IntDeque::const_iterator ConstIter;

Iter i;
ConstIter ci;
// ...
if (i == ci) ...  // 比较一个iterator和const_iterator

真正比较的时候,应该需要把iterator隐式转换成const_iterator,但是如果在某些STL的实现中,const_iterator重载的operator==运算符被实现为成员函数的话,等于号左边必须为函数的调用方,但是这种情况下调用方在等于号右边,所以就会编译错误。如果operator==被重载为非成员函数的话就不会有这样的问题。

不仅仅是判等,在同一个表达式中混用iteratorconst_iterator就会产生上面的问题,比如试图在两个迭代器之间相减时:

if (i - ci >= 3)  ...  // 如果i和ci之间至少有三个元素

这个表达式同样有可能产生编译错误,我们可以用下面的表达式来替代

if (ci + 3 <= i) ...

但是这样又产生了新的问题,迭代器ci + 3并不总是有效的,它可能超过了容器的范围。

所以显然在两种迭代器之间抉择的时候,选择iterator可以避免很多不必要的问题。

使用distance和advance将const_iterator转换成iterator

使用强制类型转换是行不通的,像下面的代码是无法通过编译的

image-20230907104327016

因为从const_iteratoriterator并没有隐式类型转换的途径,那么如果该用下面这句话呢

Iter i(const_cast<Iter>(ci));

仍然会产生编译错误,因为针对deque来说,iteratorconst_iterator是完全不同的类,进行强制类型转换是完全没有意义的。对于vector/string类来说,强制类型转换的方法可能会通过编译,因为对于这两个容器的大部分实现来说,iteratorconst_iterator通过T*const T*来实现,但是在这样的实现下,将const_reverse_iteratorreverse_iterator还是两个完全不同的类。

正确的思路如下

IntDeque d;
ConstIter ci;

// ci指向d的某个位置

Iter i(d.begin());
advance(i, distance(i, ci));  // 移动i指向ci的位置

但是上面的代码还是不能通过编译,distance的声明如下

template<typename InputIterator>
typename iterator_traits<InputIterator>::difference_type
distance(InputIterator first, InputIterator last);

可以发现firstlast是两个相同的类型,这就导致了模版实例化的时候会产生二义性,为了消除二义性,我们手动指定模版参数即可

advance(i, distance<ConstIter>(i, ci));

这次就可以通过编译了。

但是对于非随机访问的迭代器来说,将const_iterator转换为iterator需要线性的时间,所以在一开始还是尽量使用iterator来代替const_iterator

正确理解reverse_iteratorbase()产生的iterator

reverse_iteratorbase()产生的iterator并不指向同一个元素,在下面的代码中

image-20230907114026017

image-20230907114201162

所以在使用base产生的iterator的时候就需要考虑偏移产生的影响。

  • 当执行插入操作时,使用base产生的i作为位置传入insert中,会在i的前面插入一个新的元素,新插入的元素在逆序遍历时正好处在期望的位置
    放到上面的图示中,实际上就是在3,4之间插入了一个新元素

  • 如果要删除ri指向的元素时,直接使用ri.base()就不对了,应该的使用方法是

    v.erase(--ri.base());
    

    书中说这行代码编译不通过,但是我测试是可以的,在网上也没有找到答案,书中建议的做法如下

    v.erase((++ri).base());
    

对逐个字符的输入考虑使用istreambuf_iterator

如果想要把一个文本文件内容拷贝到一个string对象中,下面是一种看上去比较合理的解决方法

image-20230907142445360

但是这段代码并没有把文件中的空白字符读进去

image-20230907142527010

这是因为istream_iterator使用operator>>函数来完成实际的读操作,而默认情况下operator>>会跳过空白字符。

假如需要跳过空白字符,我们可以通过某些操作来改变默认行为
image-20230907143343617

这样就可以正确读入空白字符了。

但是这样效率比较低,反复调用operator>>会有很大的开销,我们可以使用istreambuf_iterator来替代istream_iteratoristreambuf_iterator<char>直接从流的缓冲区读取一个字符,我们只需要把代码改成下面这样,就既可以读取空白字符,而且效率还更高
image-20230907144029340

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

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

相关文章

XP小皮面板中的Mysql启动就停止,本地Mysql无法启动解决方法

前言&#xff1a; XP小皮面板中的mysql启动就停止&#xff0c;尝试查看很多方法无效&#xff0c;任务管理器mysql也尝试了先终止后启动&#xff0c;没反应... 解决方法 打开CMD&#xff0c;输入命令行 sc delete Mysql 这个命令是删除本地Mysql服务 然后再点开小皮的…

数学计算式转为表达式树

数据结构“栈”的一个用途就是&#xff1a;平衡符号&#xff0c;比如这样一个代数式&#xff1a;&#xff08;a(bc)*a(e*fa*(cd))&#xff09;,你能一眼看出这个式子的括号是否正确吗&#xff1f; 更何况还可以加入中括号&#xff08;[]&#xff09;,大括号&#xff08;{}&…

harmony应用签名

1. 随便搞个halloworld程序 2.生成私匙与证书请求文件 我就是key store file选择了一个文件夹&#xff0c;又不给任何提示&#xff0c;等我输入密码时才提示 填写图中内容即可&#xff0c;图中未填项可不填 点击完成即可

CPSE深圳充换电展开幕,飞凌嵌入式引领智能充储技术新潮流

9月6日&#xff0c;2023第六届深圳国际充电桩及换电站展览会&#xff08;简称&#xff1a;CPSE深圳充换电展&#xff09;在深圳会展中心&#xff08;福田&#xff09;开幕&#xff0c;飞凌嵌入式如期亮相&#xff0c;与来自全国的客户朋友及合作伙伴一同交流分享企业在智能充电…

WebDAV之π-Disk派盘 + 天悦日记

天悦日记是一款清爽简约的日记记录工具,通过天悦日记app随时随地快速写日记,更有智能数据统计分析报表,多端同步多种备份,本地备份和基于WebDAV协议的云端备份。跨平台使用,支持多设备、多平台无差别使用。天悦日记将每一天经历都清晰记录在手机,一目了然知道曾经的经历,…

StarRocks数据库FE——Catalog层

​仓外挂湖是指以 MPP 数据库为基础&#xff0c;使用可插拔架构&#xff0c;通过开放接口对接外部存储实现统一存储&#xff0c;在存储底层共享一份数据&#xff0c;计算、存储完全分离&#xff0c;实现从强管理到兼容开放存储和多引擎。实现方向为增加存储能力&#xff0c;提升…

Blender之锁定摄像机到视图方位

文章目录 当你在blender 中时&#xff0c;想要让你的摄像机跟随你的视图方位&#xff0c;以方便你的后期的制作&#xff0c;那应该怎么半&#xff1f; 先点击摄像机的图标&#xff0c;进入摄像机视图 然后按一下键盘的N 键&#xff0c;进入编辑模式&#xff0c;选择视图 最后…

【笔试强训选择题】Day34.习题(错题)解析

作者简介&#xff1a;大家好&#xff0c;我是未央&#xff1b; 博客首页&#xff1a;未央.303 系列专栏&#xff1a;笔试强训选择题 每日一句&#xff1a;人的一生&#xff0c;可以有所作为的时机只有一次&#xff0c;那就是现在&#xff01;&#xff01;&#xff01;&#xff…

蓝天转债,双良转债上市价格预测

蓝天转债111017 基本信息 转债名称&#xff1a;蓝天转债&#xff0c;评级&#xff1a;AA&#xff0c;发行规模&#xff1a;8.7亿元。 正股名称&#xff1a;蓝天燃气&#xff0c;今日收盘价&#xff1a;9.74元&#xff0c;转股价格&#xff1a;10.13元。 当前转股价值 转债面值…

阿里巴巴API接口解析,实现获得商品详情

要解析阿里巴巴API接口并实现获取商品详情&#xff0c;你需要按照以下步骤进行操作&#xff1a; 了解阿里巴巴开放平台&#xff1a;访问阿里巴巴开放平台&#xff0c;并了解相关的API文档、开发者指南和规定。注册开发者账号&#xff1a;在阿里巴巴开放平台上注册一个开发者账…

【Unity编辑器扩展】| Inspector监视器面板扩展

前言【Unity编辑器扩展】| Inspector监视器面板扩展一、ContextMenu和ContextMenuItem二、Custom Editors 自定义编辑器三、Property Drawer 属性绘制器总结前言 前面我们介绍了Unity中编辑器扩展的一些基本概念及基础知识,还有编辑器扩展中用到的相关特性Attribute介绍。后面…

C高级文件相关指令

使用cut截取出Ubuntu用户的家目录&#xff0c;要求:不能使用“&#xff1a;”作为分隔 XMind

嵌入式Linux驱动开发(LCD屏幕专题)(三)

1. 硬件相关的操作 LCD驱动程序的核心就是&#xff1a; 分配fb_info设置fb_info注册fb_info硬件相关的设置 硬件相关的设置又可以分为3部分&#xff1a; 引脚设置时钟设置LCD控制器设置 2. 在设备树里指定LCD参数 framebuffer-mylcd {compatible "100ask,lcd_drv&qu…

E. Nastya and Potions

Problem - E - Codeforces 思路&#xff1a;想到用图论前驱图了&#xff0c;但是因为考虑可能有环的存在&#xff0c;但是其实题干中说明了不能通过一种或几种混合得到自己&#xff0c;所以就保证了不存在环&#xff0c;那就能用拓扑结构的性质做&#xff0c;用记忆化搜索就可以…

DHCP的interface(接口),global(全局)配置以及DHCP relay(中继),DHCP snooping,DHCP option

目录 1.DHCP的接口&#xff08;interface&#xff09;配置 2.DHCP的全局&#xff08;global&#xff09;配置 3.dhcp relay 4.dhcp snooping 5.option 这里有一个简单的拓扑图 交换机配置命令如下 The device is running!<Huawei> <Huawei>sys Enter system …

go语言基本操作---五

error接口的使用 Go语言引入了一个关于错误处理的标准模式&#xff0c;即error接口&#xff0c;它是Go语言内建的接口类型 type error interface {Error() string }package mainimport ("errors""fmt" )type Student struct {name stringid int }func …

【 XXL-JOB】 XXL-JOB任务分片

文章目录 前言xxl-job 分片广播任务的详细教程创建任务编写任务代码分片参数设置执行任务查看任务执行结果示例1示例2 总结 前言 xxl-job 是一个分布式任务调度平台&#xff0c;支持定时任务和分片任务。其中&#xff0c;分片任务可以将一个大任务拆分成多个小任务&#xff0c…

用vagrant快速创建linux虚拟机

参考B站&#xff1a;https://www.bilibili.com/video/BV1np4y1C7Yf 1、下载VirtualBox 2、下载vagrant 3、vagrant官网下载.box文件 官网&#xff1a;https://app.vagrantup.com/boxes/search 例如要下载这个centos/7 点进去&#xff0c;点击下载 下载后放到一个指定目录…

qt作业day2

//widget.cpp#include "widget.h" #include "ui_widget.h"void Widget::usr_login() {if("admin" this->edit_acc->text()){if("123456" this->edit_psd->text()){speech->say("登录成功");emit jump_sig1…

latex修改公式的默认编号

文章目录 问题描述省流出错演示没有载入amsmath包载入amsmath包 总结 问题描述 有时想自己定义公式的编号&#xff0c;不想用默认的编号(1) (2)…&#xff0c;我们应该怎么做呢&#xff1f; 只需看本文一分钟就能解决。 省流 开头载入amsmath包&#xff0c;然后在公式后面加…