看了候哥的《STL源码剖析》的迭代器那一章,在这里将思路稍微疏理一下

迭代器

迭代器模式的定义:提供一种方法,在不需要暴露某个容器的内部表现形式情况下,使之能依次访问该容器中的各个元素。

  迭代器在STL中得到了广泛的应用,通过迭代器,容器和算法可以有机的粘合在一起,只要对算法给予不同的迭代器,就可以对不同容器进行相同的操作。也就是说,数据容器和算法是分开的。    

  独立的迭代器并不能满足我们的要求,在实现独立的迭代器时无可避免的会暴露出容器中的很多内容,所以STL将迭代器的实现交给了容器,每种容器都会以嵌套的方式在内部定义专属的迭代器。各种迭代器的接口相同,内部实现却不相同,这也直接体现了泛型编程的概念。 
迭代器依附于具体的容器,即不同的容器有不同的迭代器实现。

对于泛型算法find,只要给它传入不同的迭代器,就可以对不同的容器进行查找操作。迭代器起穿针引线的作用,有效地实现了算法对不同容器的访问。

/*STL 中的 find 方法的实现*/
template<class InputIterator, class T>
InputIterator Find(InputIterator first, InputIterator last, const T& value)
{
while (first != last && *first != value)
++first;
return first;
} /*迭代器作为粘合剂的例子*/
void IteratorTest()
{
const int arr[] = { , , , , , , , , , }; vector<int> Vector(arr, arr + ); //vector 的初始化
list<int> List(arr, arr + ); //list 的初始化
deque<int> Deque(arr, arr + ); //deque 的初始化 vector<int>::iterator it1 = Find(Vector.begin(), Vector.end(), );
cout << *it1 << endl; list<int>::iterator it2 = Find(List.begin(), List.end(), );
cout << *it2 << endl; deque<int>::iterator it3 = Find(Deque.begin(), Deque.end(), );
if (it3 == Deque.end())
cout << "Node Found : Data!" << endl;
}

迭代器是一种smart pointer

迭代器是一种智能指针,是一种行为类似指针的对象,它内部封装了一个原始指针,并重载了operator*() 和operator->()等操作。

链表的迭代器

template<typename T>
class ListIter
{
public:
ListIter(T *p = ) : m_ptr(p){} //解引用,即dereference
T& operator*() const { return *m_ptr;} //成员访问,即member access
T* operator->() const { return m_ptr;} //前置++操作
ListIter& operator++()
{
m_ptr = m_ptr->next(); //暴露了ListItem的东西
return *this;
} //后置++操作
ListIter operator++(int)
{
ListIter temp = *this;
++*this;
return temp;
} //判断两个ListIter是否指向相同的地址
bool opeartor==(const ListIter &arg) const { return arg.m_ptr == m_ptr;} //判断两个ListIter是否指向不同的地址
bool operator!=(const ListIter &arg) const { return arg.m_ptr != m_ptr;} private:
T *m_ptr;
};

链表的实现

//List节点的结构
template<typename T>
class ListItem
{
public:
ListItem() { m_pNext = ;}
ListItem(T v, ListItem *p = ) { m_value = v; m_pNext = p;}
T value() const { return m_value;}
ListItem* next() const { return m_pNext;} private:
T m_value; //存储的数据
ListItem* m_pNext; //指向下一个ListItem的指针
}; //List表的结构
template<typename T>
class List
{
public:
//从链表尾部插入元素
void Push(T value)
{
m_pTail = new ListItem<T>(value);
m_pTail = m_pTail->next();
} //返回链表头部指针
ListItem<T>* begin() const { return m_pHead;} //返回链表尾部指针
ListItem<T>* end() const { return m_pTail;} //其它成员函数 private:
ListItem<T> *m_pHead; //指向链表头部的指针
ListItem<T> *m_pTail; //指向链表尾部的指针
long m_nSize; //链表长度
};

traits编程技法

5种迭代器型别的简单介绍:

1.value_type:迭代器所指对象的类型,原生指针也是一种迭代器,对于原生指针int*,int即为指针所指对象的类型,也就是所谓的value_type。

2.difference_type用来表示两个迭代器之间的距离,对于原生指针,STL以C++内建的ptrdiff_t作为原生指针的difference_type。

3.reference_type是指迭代器所指对象的类型的引用,reference_type一般用在迭代器的*运算符重载上,如果value_type是T,那么对应的reference_type就是T&;如果value_type是const T,那么对应的reference_type就是const T&。

4.pointer_type就是相应的指针类型,对于指针来说,最常用的功能就是operator*和operator->两个运算符。

5.iterator_category的作用是标识迭代器的移动特性和可以对迭代器执行的操作,从iterator_category上,可将迭代器分为Input Iterator、Output Iterator、Forward Iterator、Bidirectional Iterator、Random Access Iterator五类,这样分可以尽可能地提高效率。

在定义自己的类时为了和 STL 兼容,必须包含如上 5 个型别,以便 traits 的萃取。下面是STL提供的  iterator class,如果每个新设计的迭代器都继承它,就可以保证符合STL规范了

template<typename Category,
typename T,
typename Distance = ptrdiff_t,
typename Pointer = T*,
typename Reference = T&>
struct iterator
{
typedef Category iterator_category;
typedef T value_type;
typedef Distance difference_type;
typedef Pointer pointer;
typedef Reference reference;
}; //类iterator不包含任何成员变量,只有类型的定义,因此不会增加额外的负担。由于后面三个类型都有默认值,在继承它的时候,只需要提供前两个参数就可以了。

迭代器的分类

前面提到迭代器的分类,下面我们就简单讨论下迭代器的分类。

除了原生指针以外,迭代器被分为五类:

Input Iterator 
此迭代器不允许修改所指的对象,即是只读的。支持==、!=、++、*、->等操作。

Output Iterator 
允许算法在这种迭代器所形成的区间上进行只写操作。支持++、*等操作。

Forward Iterator 
允许算法在这种迭代器所形成的区间上进行读写操作,但只能单向移动,每次只能移动一步。支持Input Iterator和Output Iterator的所有操作。

Bidirectional Iterator 
允许算法在这种迭代器所形成的区间上进行读写操作,可双向移动,每次只能移动一步。支持Forward Iterator的所有操作,并另外支持–操作。

Random Access Iterator 
包含指针的所有操作,可进行随机访问,随意移动指定的步数。支持前面四种Iterator的所有操作,并另外支持it + n、it - n、it += n、 it -= n、it1 - it2和it[n]等操作。

迭代器的分类和从属关系可用下面的图表示(注意,这里的箭头并不代表继承关系,而是一种概念上的联系):

分类的原因:

设计算法时,如果可能,我们尽量针对上面某种迭代器提供一个明确定义,并针对更强化的某种迭代器提供另一种定义,这样才能在不同情况下提供最大效率。

比如,有个算法可接受Forward Iterator,但是你传入一个Random Access Iterator,虽然可用(Random Access Iterator也是一种Forward Iterator),但是不一定是最佳的,因为Random Access Iterator可能更加臃肿,效率不一定高。

使用继承的原因:

例:

下面进入正题 traits 类型萃取机:

欢迎交流~~

迭代器(iterator) 与 traits 编程技法的更多相关文章

  1. 迭代器iterator和traits编程技法

    前言 这段时间研读SGI-STL-v2.91源码,并提炼核心代码自己实现一遍,感觉受益颇深.觉得有必要写一些文章记录下学习过程的思考,行文旨在总结,会大量参考侯捷<STL源码剖析>的内容. ...

  2. STL源码--iterator和traits编程技法

    第一部分 iterator学习 STL iterators定义: 提供一种方法,使之能够依序巡访某个聚合物(容器)所含的各个元素,而又无需暴露该聚合物的内部表达方式. 任何iteartor都应该提供5 ...

  3. 迭代器概念与traits编程技法

    //迭代器是一种smart pointer template<typename T> class ListItem { public: T value() const { return _ ...

  4. STL源码分析读书笔记--第三章--迭代器(iterator)概念与traits编程技法

    1.准备知识 typename用法 用法1:等效于模板编程中的class 用法2:用于显式地告诉编译器接下来的名称是类型名,对于这个区分,下面的参考链接中说得好,如果编译器不知道 T::bar 是类型 ...

  5. STL——迭代器与traits编程技法

    一.迭代器 1. 迭代器设计思维——STL关键所在 在<Design Patterns>一书中对iterator模式定义如下:提供一种方法,使之能够依序巡访某个聚合物(容器)所含的各个元素 ...

  6. 【STL 源码剖析】浅谈 STL 迭代器与 traits 编程技法

    大家好,我是小贺. 点赞再看,养成习惯 文章每周持续更新,可以微信搜索「herongwei」第一时间阅读和催更,本文 GitHub : https://github.com/rongweihe/Mor ...

  7. STL Traits编程技法

    traits编程技法大量运用于STL实现中.通过它在一定程度上弥补了C++不是强型别语言的遗憾,增强了C++关于型别认证方面的能力. traits编程技法是利用“内嵌型别”的编程技法和编译器的temp ...

  8. STL中的Traits编程技法

    最近在看读<STL源码剖析>,看到Traits编程技法这节时,不禁感慨STL源码作者的创新能力.那么什么是Traits编程技法呢?且听我娓娓道来: 我们知道容器的许多操作都是通过迭代器展开 ...

  9. STL源码之traits编程技法

    摘要 主要讨论如何获取迭代器相应型别.使用迭代器时,很可能用到其型别,若需要声明某个迭代器所指对象的型别的变量,该如何解决.方法如下: function template的参数推导机制 例如: tem ...

随机推荐

  1. Python实现ID3算法

    自己用Python写的数据挖掘中的ID3算法,现在觉得Python是实现算法的最好工具: 先贴出ID3算法的介绍地址http://wenku.baidu.com/view/cddddaed0975f4 ...

  2. Solr4.8.0源码分析(9)之Lucene的索引文件(2)

    Solr4.8.0源码分析(9)之Lucene的索引文件(2) 一. Segments_N文件 一个索引对应一个目录,索引文件都存放在目录里面.Solr的索引文件存放在Solr/Home下的core/ ...

  3. jQuery的选择器中的通配符[id^='code'] 【转】

    JQuery 1.选择器 (1)通配符: $("input[id^='code']");//id属性以code开始的所有input标签 $("input[id$='cod ...

  4. 将excel里面的数据导入到程序里面

    页面布局 <table> <tr> <td style="padding-top: 16px; padding-left: 36px;"> &l ...

  5. windows下和linux下 Redis 安装

    Redis 是一个高性能的key-value数据库, 使用内存作为主存储,数据访问速度非常快,当然它也提供了两种机制支持数据持久化存储.比较遗憾的是,Redis项目不直接支持Windows,Windo ...

  6. Android的布局优化之include、merge 、viewstub

    以前在写布局的时候总是喜欢用自己熟悉的方式去写,从来也没有想过优化怎么的,后来又一次在上班的时候老大拿着我写的一个页面说我这个不行.我说这不是和设计图上的一模一样的么?怎么就不行了?然后他就跟我说了一 ...

  7. 矢量做图组件OTGisX的使用(类似Mapbase)

    一:组件添加到工具栏 要在应用程序中应用OTGisX控件,首先要把所下载的OTGisX组件添加到.Net工程中.并将其添加到工具箱托盘中.添加方式为:在工具箱上单击右键,选择“选择项”,会出现“选择工 ...

  8. hihocoder1236(北京网络赛J):scores 分块+bitset

    北京网络赛的题- -.当时没思路,听大神们说是分块+bitset,想了一下发现确实可做,就试了一下,T了好多次终于过了 题意: 初始有n个人,每个人有五种能力值,现在有q个查询,每次查询给五个数代表查 ...

  9. 9月1日,请记得备好名片来PechaKucha Night和大家“闲聊” | Hi!设计

    9月1日,请记得备好名片来PechaKucha Night和大家"闲聊" | Hi!设计 9月1日,请记得来PechaKucha Night和大家"闲聊"

  10. X Window、GNOME和KDE之间的关系

    原文地址:http://blog.csdn.net/jincf2011/article/details/6362923 X Window, 即X Windows图形用户接口,它并不是一个软件,而是一个 ...