STL源码分析之迭代器
前言
迭代器是将算法和容器两个独立的泛型进行调和的一个接口. 使我们不需要关系中间的转化是怎么样的就都能直接使用迭代器进行数据访问. 而迭代器最重要的就是对operator *
和operator->
进行重载, 使它表现的像一个指针.
类型
迭代器根据移动特性和实施操作被分为5类
- input iterator(输入迭代器) : 迭代器所指的内容不能被修改, 只读且只能执行一次读操作.
- output iterator(输出迭代器) : 只写并且一次只能执行一次写操作.
- forward iterator(正向迭代器) : 支持读写操作且支持多次读写操作.
- bidirectional iterator(双向迭代器) : 支持双向的移动且支持多次读写操作.
- random access iterator(随即访问迭代器) : 支持双向移动且支持多次读写操作. p+n, p-n等.
1~4类迭代器执行操作的就如 : p++, ++p, p->而不是5类的p+n操作. 不明白的我们下面会进行讲解.
源码分析
category的五类迭代器以及继承关系
struct input_iterator_tag {};
struct output_iterator_tag {};
struct forward_iterator_tag : public input_iterator_tag {};
struct bidirectional_iterator_tag : public forward_iterator_tag {};
struct random_access_iterator_tag : public bidirectional_iterator_tag {};
这五个类都是空类, 只是为了之后调用时通过类选择不同的重载函数. 继承是为了可以使用传递调用,当不存在某种迭代器类型匹配时编译器会依据继承层次向上查找进行传递, 就可以通过继承关系来决定选择最优的调用. 我们通过用distance
来讲最优.
distance
是用于计算连个迭代器之间的距离, 因为重载就可以通过不同的迭代器类型选择不同的函数来提高效率.
这里distance
的iterator_category
函数是每个迭代器自己定义的, 跟traits
萃取器相关我准备放在下一篇章讲解. 这里只要知道它能通过first
参数推断出是哪一类的迭代器从而选择调用哪一个函数.
template <class InputIterator, class Distance>
inline void distance(InputIterator first, InputIterator last, Distance& n)
{
__distance(first, last, n, iterator_category(first));
}
template <class InputIterator, class Distance>
inline void __distance(InputIterator first, InputIterator last, Distance& n,
input_iterator_tag)
{
while (first != last)
{ ++first; ++n; }
}
template <class RandomAccessIterator, class Distance>
inline void __distance(RandomAccessIterator first, RandomAccessIterator last,
Distance& n, random_access_iterator_tag)
{
n += last - first;
}
从distance
源码可以看出来不同的迭代器的计算方式并不一样, random_access_iterator_tag
的距离的计算效率最高, 其他都是通过++
操作来依次访问. 当然random_access_iterator_tag
类的迭代器也是可以调用input_iterator_tag
, 但是显然效率很低, 所以不同的迭代器最自己最佳的效率. 通过iterator_category
进行最优选择.
五类迭代器源码
五类迭代器的结构体, 可以看出来每个类都定义了相同的变量名. 但是每个名的类型不一定一样, 提供统一的名是为了traits
进行类型萃取. 每个类的iterator_category
都是代表了不同的迭代器, 通过它来选择该迭代器执行的函数.
template <class T, class Distance> struct input_iterator
{
typedef input_iterator_tag iterator_category;
typedef T value_type;
typedef Distance difference_type;
typedef T* pointer;
typedef T& reference;
};
struct output_iterator {
typedef output_iterator_tag iterator_category;
typedef void value_type;
typedef void difference_type;
typedef void pointer;
typedef void reference;
};
template <class T, class Distance> struct forward_iterator {
typedef forward_iterator_tag iterator_category;
typedef T value_type;
typedef Distance difference_type;
typedef T* pointer;
typedef T& reference;
};
template <class T, class Distance> struct bidirectional_iterator {
typedef bidirectional_iterator_tag iterator_category;
typedef T value_type;
typedef Distance difference_type;
typedef T* pointer;
typedef T& reference;
};
template <class T, class Distance> struct random_access_iterator {
typedef random_access_iterator_tag iterator_category;
typedef T value_type;
typedef Distance difference_type;
typedef T* pointer;
typedef T& reference;
};
iterator_category
判断传入迭代器的类型
template <class Iterator>
inline typename iterator_traits<Iterator>::iterator_category
iterator_category(const Iterator&) {
typedef typename iterator_traits<Iterator>::iterator_category category;
return category();
}
总结
这一篇仅仅只是讲解了一些关于迭代器类型, 和一点traits
的一点用法. 关于每个迭代器都设置为相同的类型名都是为了traits
萃取器做准备. 下篇进行探讨.
STL源码分析之迭代器的更多相关文章
- STL源码分析《4》----Traits技术
在 STL 源码中,到处可见 Traits 的身影,其实 Traits 不是一种语法,更确切地说是一种技术. STL库中,有一个函数叫做 advance, 用来将某个迭代器(具有指针行为的一种 cla ...
- STL源码分析读书笔记--第二章--空间配置器(allocator)
声明:侯捷先生的STL源码剖析第二章个人感觉讲得蛮乱的,而且跟第三章有关,建议看完第三章再看第二章,网上有人上传了一篇读书笔记,觉得这个读书笔记的内容和编排还不错,我的这篇总结基本就延续了该读书笔记的 ...
- STL源码分析《3》----辅助空间不足时,如何进行归并排序
两个连在一起的序列 [first, middle) 和 [middle, last) 都已经排序, 归并排序最核心的算法就是 将 [first, middle) 和 [middle, last) 在 ...
- STL 源码分析《1》---- list 归并排序的 迭代版本, 神奇的 STL list sort
最近在看 侯捷的 STL源码分析,发现了以下的这个list 排序算法,乍眼看去,实在难以看出它是归并排序. 平常大家写归并排序,通常写的是 递归版本..为了效率的考虑,STL库 给出了如下的 归并排序 ...
- STL 源码分析《2》----nth_element() 使用与源码分析
Select 问题: 在一个无序的数组中 找到第 n 大的元素. 思路 1: 排序,O(NlgN) 思路 2: 利用快排的 RandomizedPartition(), 平均复杂度是 O(N) 思路 ...
- STL源码分析与实现-stl_list容器
1. stl_list 介绍 今天我们来总结一下stl_List, 通过之前介绍单链表的文章,其实对链表的基本操作已经十分熟悉了,那对于stl_list,无非就是链表结构不一样,至于其中的增删改查的细 ...
- STL 源码分析六大组件-allocator
1. allocator 基本介绍 分配器(allocator))是C ++标准库的一个组件, 主要用来处理所有给定容器(vector,list,map等)内存的分配和释放.C ++标准库提供了默认使 ...
- stl源码分析之allocator
allocator封装了stl标准程序库的内存管理系统,标准库的string,容器,算法和部分iostream都是通过allocator分配和释放内存的.标准库的组件有一个参数指定使用的allocat ...
- STL源码剖析:迭代器
准备知识 什么是迭代器? 迭代器是链接容器和算法的桥梁,所有的算法都通过迭代器操作容器中的数据 迭代器是一种智能指针,最重要的操作符重载就是operator*,operator-> 迭代器的实现 ...
随机推荐
- org.apache.solr.handler.dataimport.DataImportHandlerException: Data Config problem: 对实体 "characterEn
解决的方法:在配置数据库连接是讲url里的特殊符号要做转义 jdbc:mysql://IP:3306/数据库名?useUnicode=true&characterEncoding=utf8 改 ...
- BestCoder Round #60/HDU 5505 暴力数学
GT and numbers 问题描述 给出两个数NN和MM. NN每次可以乘上一个自己的因数变成新的NN. 求最初的NN到MM至少需要几步. 如果永远也到不了输出-1−1. 输入描述 第一行读入一个 ...
- MapReduce04
===================== MapReduce内部机制:本地性 ===================== 什么是数据本地性(data locality)--------------- ...
- RAID5配置及服务器2003系统安装方法。2000系统的安装要使用7.9版本的引导盘
服务器2003系统安装方法.2000系统的安装要使用7.9版本的引导盘 RAID5配置: 1.为新到的惠普DL380服务器装系统,首先要配置RAID阵列. 如下图进行配置. 启动到如上图阶段,按F8. ...
- C# 获得资源文件下图片的路径
最终实现正确的代码是: button8.Image = System.Drawing.Image.FromFile(@"..\\..\\Resources\\GAOJIBAN.png&quo ...
- P3052 [USACO12MAR]摩天大楼里的奶牛Cows in a Skyscraper 状压dp
这个状压dp其实很明显,n < 18写在前面了当然是状压.状态其实也很好想,但是有点问题,就是如何判断空间是否够大. 再单开一个g数组,存剩余空间就行了. 题干: 题目描述 A little k ...
- 杂项-JSP-Runoob:JSP 标准标签库(JSTL)
ylbtech-杂项-JSP-Runoob:JSP 标准标签库(JSTL) 1.返回顶部 1. JSP 标准标签库(JSTL) JSP标准标签库(JSTL)是一个JSP标签集合,它封装了JSP应用的通 ...
- Android开发中常用的一些小技巧(转载)
http://www.jb51.net/article/61135.htm Activity.startActivities() 常用于在应用程序中间启动其他的Activity. TextUtils. ...
- python自动化测试学习笔记-5常用模块
上一次学习了os模块,sys模块,json模块,random模块,string模块,time模块,hashlib模块,今天继续学习以下的常用模块: 1.datetime模块 2.pymysql模块(3 ...
- 灾备还原之gitlab
灾备还原之gitlab 备份情景:服务器A架设了gitlab,定期通过duplicity发送加密备份给B服务器,现在由于某种情况生产机器A完全无法访问(主机商跑路?硬盘冒烟?服务器BOOM了?),本地 ...