C++11 你真的会用迭代器(iterator)么?

10km
博客专家认证
2015-11-22 10:56:06
加精
C++ STL提供了丰富的标准容器(Container)对象(vector,array,queue,list,set,unordered_map/set...),让我们可以根据需求选择不同的容器管理各种类型的数据。说到使用容器,不用迭代器(iterator)是不可能的,所有的容器对象都根据容器的特点都提供了类似但不同的iterator,用于访问容器中的数据。

迭代器(iterator)循环
---------------

一般来说,如果要遍历一个容器中的所有数据,程序员们最常用的写法是:
#include <list>
#include <iostream>
int main(){
list<int> lst;
for(list<int>::iterator itor=lst.begin();itor!=lst.end();itor++){
cout<<(*itor)<<endl;
//do something
}
}



基于范围的for循环
----------

C++11提供了关于for循环的新特性:基于范围的for循环( the range-base for statement),再加上"类型推导"特性可以将上面的代码进一步简化:

for(auto &node:lst){
cout<<node<<endl;
//do something
}



没有区别吗?
--

显然,新的for循环写法更简洁,但新的for循环写法的优点仅此而已吗?
仔细琢磨,你会注意到,第一种写法,每次循环,都要调用`lst.end()`,

这是list.end()函数的源代码(来自C++11中头文件`stl_list.h`):


/**
* Returns a read/write iterator that points one past the last
* element in the %list. Iteration is done in ordinary element
* order.
*/
iterator
end() _GLIBCXX_NOEXCEPT
{ return iterator(&this->_M_impl._M_node); }


可以看出,每一次调用end()函数,都会返回一个`iterator`对象,根据迭代器的特性我们可以知道在整个迭代循环过程中,每次调用`end()`返回的对象其实都是完全一样的,而每次的调用都不可避免会发生对象构造、复制。。。等等动作,这对于要求高性能的应用场合,这种无意义的重复是不可接受的。

那么基于范围的for循环( the range-base for statement)会不会是同样的处理方式呢?
为了验证这个问题,我做了一个试验:
在我的上一篇文章
C++11 为自定义容器实现标准的forward迭代器》中我实现了一个基于自定义哈希表(`HashTableAbstract`)的标准forward迭代器。于是我在HashTableAbstract 的end()函数中加入了调试代码,这样每次`end()`都会输出调试信息:

iterator end()noexcept
//{ return iterator(this->m_table,this->m_table.capacity); }//原代码
{
cout << "return a end iterator" << endl;//输出调试信息
return iterator(this->m_table, this->m_table.capacity);
}


然后运行如下测试代码:

HashSetCl<int> testhash;//HashSetCl是基于HashTableAbstract子类,实现哈希集合
testhash.insert(2000);//加入3条数据
testhash.insert(65535);
testhash.insert(12345);
cout<<"testing for statement using iterator:"<<endl;//使用迭代器循环
for (auto itor = testhash.begin(); itor != testhash.end(); itor++) {
cout << *itor << endl;
}
cout<<"testing for the range-base for statement:"<<endl;//使用基于范围的for循环
for (auto n : testhash) {
cout << n << endl;
}

以下是程序输出(debug/release结果一样)
引用
testing for statement using iterator://注,循环中调用了三次end()
return a end iterator
2000
return a end iterator
12345
return a end iterator
65535
return a end iterator
testing for the range-base for statement://注,循环中调用了一次end()
return a end iterator
2000
12345
65535

总结
--

上面的输出可以证实,基于范围的for循环( the range-base for statement)只会在循环开始的时候调用一次`end()`,与一般直接使用迭代器(iterator)的循环相比,不仅具备代码更简洁的优点,性能上也更具备优势

如果你还是"坚持传统",习惯直接使用迭代器来工作,那么建议对代码做一些改进,还以最前面的代码为例,在循环开始时调用一次`end()`函数保存成临时变量`end`,然后每次循环比较的时候不再调用`end()`函数,而是直接与临时变量`end`相比,就避免了重复调用`end()`。

for(auto itor=lst.begin(),end=lst.end();itor!=end;itor++){
cout<<(*itor)<<endl;
//do something
}
...全文
7676 17 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
mmadd3 2015-12-02
  • 打赏
  • 举报
回复
vb 好 、
taanniu1 2015-12-02
  • 打赏
  • 举报
回复
引用 9 楼 gemo 的回复:
整天研究这些东西是c++的悲哀
每个知识点,总要有人深入研究的!对于规范使用C++,高效使用C++ 是有帮助的
zhxingway 2015-12-02
  • 打赏
  • 举报
回复
c++11编译时有什么限制么?
钮牛 2015-12-01
  • 打赏
  • 举报
回复
迭代器很方便啊,用着挺好的
Will. Liu 2015-12-01
  • 打赏
  • 举报
回复
引用 9 楼 gemo 的回复:
整天研究这些东西是c++的悲哀
正解!
蓝鹰 2015-11-30
  • 打赏
  • 举报
回复
可以少敲几个键,但我老大用的旧的编译器。他编不过,所以算了。
小弟是菜鸟 2015-11-27
  • 打赏
  • 举报
回复
存在,即合理。只operator(),使用for_each的飘过。
YouNeverCanTell 2015-11-26
  • 打赏
  • 举报
回复
循环过程中迭代器可能会有失效情况发生,每次循环计算一次end()还是有必要的;不然可以先定义一个变量保存end()
gemo 2015-11-24
  • 打赏
  • 举报
回复
整天研究这些东西是c++的悲哀
  • 打赏
  • 举报
回复
以前不都是用 std::for_each 么
xiaoxiangqing 2015-11-23
  • 打赏
  • 举报
回复
迭代器越来越方便,为什么不用呢?
D41D8CD98F 2015-11-22
  • 打赏
  • 举报
回复
引用 楼主 10km 的回复:
一般来说,如果要遍历一个容器中的所有数据,程序员们最常用的写法是:
#include <list>
#include <iostream>
int main(){
list<int> lst;
for(list<int>::iterator itor=lst.begin();itor!=lst.end();itor++){
	cout<<(*itor)<<endl;
	//do something
}
}
cbegin() / cend() 表示不服。
10km 2015-11-22
  • 打赏
  • 举报
回复
引用 1 楼 zhousitiaoda 的回复:
这跟迭代器有什么关系,这是C++11的优化,而且楼主最后的建议也是有局限性的,遍历的过程中end()的值有可能会发生,比如erase。。
引用 2 楼 paschen 的回复:
开了优化以后函数会内联,基本没有效率上的开销 另推荐看;http://blog.csdn.net/ls306196689/article/details/35787955
两位说的没错,这个结论有局限性,准确的说应该是,无序容器迭代遍历(只读)的情况下,这个结论才有效 因为我是自己写了一个无序的容器,只实现forward迭代器,不能使用下标访问,而且每次循环都是只读访问没有删除动作,所以 所以 http://blog.csdn.net/ls306196689/article/details/35787955这里第一,二种方式都不在考虑之列,能选择的遍历方式只能是第3,4,5种
fefe82 2015-11-22
  • 打赏
  • 举报
回复
a range-based for statement is equivalent to
{
  auto && __range = range-init;
  for ( auto __begin = begin-expr,
    __end = end-expr;
    __begin != __end;
    ++__begin ) {
      for-range-declaration = *__begin;
      statement
  }
}
paschen 版主 2015-11-22
  • 打赏
  • 举报
回复
开了优化以后函数会内联,基本没有效率上的开销 另推荐看;http://blog.csdn.net/ls306196689/article/details/35787955
zhousitiaoda 2015-11-22
  • 打赏
  • 举报
回复
这跟迭代器有什么关系,这是C++11的优化,而且楼主最后的建议也是有局限性的,遍历的过程中end()的值有可能会发生,比如erase。。
资源下载链接为: https://pan.quark.cn/s/9e7ef05254f8 【久久在线FLASH系统】是一款专为久久在线网站打造的交互式Flash平台,集成了前台展示与后台管理功能,满足内容发布、管理和用户互动的需求。Flash技术曾广泛应用于网页动画和互动内容,尤其在早期互联网时代,在游戏、广告和多媒体教学等领域发挥了重要作用。该系统的核心包括以下几个关键方面: Flash技术:系统利用Flash创建动态图形、动画和交互内容,依赖Adobe Flash Player运行。其编程语言ActionScript支持面向对象开发,便于实现复杂逻辑和交互效果。 后台管理系统:作为系统的控制中心,后台支持内容上传、编辑、分类、权限设置、用户管理及数据分析,确保内容的有序更新与发布。 产品演示模块:用户可在线预览和体验产品功能,无需下载,通过交互式演示了解产品操作流程和优势。 数据库集成:系统与数据库紧密结合,用于存储Flash文件信息、用户数据及访问记录,实现高效的数据管理与检索。 安全性与优化:系统具备防止非法访问和数据泄露的安全机制,并对Flash内容进行优化,提升加载速度与用户体验。 响应式设计:尽管Flash主要用于桌面端,系统仍考虑多设备兼容性,通过响应式设计适配不同屏幕尺寸,提供一致体验。 API接口:系统支持与其他平台或服务通过API进行数据交互,如社交媒体分享、数据分析等,拓展功能边界。 用户体验:界面设计注重交互性与视觉效果,提升用户满意度和停留时间,增强平台吸引力。 版本控制:系统支持内容版本管理,便于追踪更新历史,方便内容维护与回滚。 性能监控:内置性能监控工具,实时跟踪系统负载与资源使用情况,及时发现并解决问题,保障系统稳定运行。 【久久在线FLASH系统】是一个综合性解决方案,融合了前端展示、后台管理、互动体验和数据分析等功能,体现了当时Web
资源下载链接为: https://pan.quark.cn/s/f989b9092fc5 BP神经网络轴承故障诊断系统是一种基于人工神经网络技术的智能诊断工具,专门用于识别和分析机械设备中轴承的故障情况。该系统的核心是BP神经网络(即反向传播神经网络),它能够模拟人脑的工作方式,通过学习和训练来处理复杂的非线性问题,从而对轴承的健康状态进行精准评估。 BP神经网络的基本结构由输入层、隐藏层和输出层构成。输入层接收来自传感器的信号,如振动数据或声音频率,这些信号反映了轴承的运行状态。隐藏层负责对输入数据进行特征提取和转换,将原始信号转化为更具价值的信息。输出层则输出最终的诊断结果,例如轴承是否正常、轻微磨损或严重损坏等。 在诊断过程中,数据预处理是至关重要的步骤。原始的振动或声学数据通常含有噪声,且不同传感器的数据可能缺乏可比性。因此,需要对这些数据进行滤波、归一化等处理,以提高数据质量。预处理后的数据随后被输入到BP神经网络中。在训练阶段,网络通过反向传播算法调整权重和阈值,使预测结果尽可能接近实际故障类型。这一过程利用了梯度下降法,通过计算误差梯度来更新网络参数,以最小化损失函数(通常是均方误差,用于衡量预测值与真实值之间的差异)。 BP神经网络的性能受到多种因素的影响,包括网络结构(如隐藏层的数量和每层的神经元数量)、学习率以及训练迭代次数等。优化这些参数对于提升诊断精度和速度至关重要。此外,为了验证和提升模型的泛化能力,通常采用交叉验证方法,将数据集分为训练集、验证集和测试集。其中,训练集用于训练网络,验证集用于调整网络参数,测试集则用于评估模型在未知数据上的表现。 总体而言,BP神经网络轴承故障诊断系统凭借其强大的学习和泛化能力,通过对机械设备振动和噪声数据的分析,能够实现对轴承故障的精确识别。该系统有助于提前发现设备故障隐患,减少停机时间,提高生产效率,对工业领域

65,187

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧