STL--迭代器--原理与实践



迭代器(iterator)是STL里面很基础也很重要的一个东西,迭代器的traits技术设计的很棒。

迭代器是一种行为类似指针的对象,因为指针最常用的是->*两个操作符,因此迭代器最重要的编程工作也是对这两个操作符的重载的实现。

初探traits技术

假设现在定义了这样一个迭代器MyIter,当我们拿到一个MyIter对象时,如何判断他的类型呢?

template<class T>
struct MyIter
{
    T* ptr;
    MyIter(T* p=0) : ptr(p) {}
    T& operator*() const { return *ptr; }
};

MyIter<int> iter(new int(1));

// What‘s type of *iter ???

STL的实现中,给MyIter添加了一个value_type的定义,然后通过MyIter::value_type取得对应的类型,这就是所谓的traits技术了。

#include <iostream>
using namespace std;

template<class T>
struct MyIter
{
    typedef T value_type;  // value_type定义
    T* ptr;
    MyIter(T* p=0) : ptr(p) {}
    T& operator*() const { return *ptr; }
};

template<class I>
typename I::value_type     // typename用于指明I::value_type是个类型, 并且作为返回值类型
func(I ite)
{
    return *ite;
}

int main(int argc, char **argv)
{
    MyIter<int> ite(new int(8)); //定义了一个对象,模板参数是int, 对象中的ptr指针指向了数值8
    cout << func(ite) << endl; // 

    return 0;
}
// 输出8

函数模板中的参数类型IMyIter , 函数返回值类型是MyIter::value_type, return *ite即使执行重载后的*返回值.

使用萃取技术,那么函数可以针对任意返回类型都是允许的,因为传递给函数的参数是迭代器(指针),萃取技术就是从迭代器类型(迭代器类)中获取返回值的类型。

迭代器类的构造是通过指定的模版参数值类型int构造的.

上面的代码中通过模板参数的value_type来推导出具体的类型,注意typename用于指明I::value_type是个类型,如果没有typename的话,编译器将把value_type当成I的一个member或者member function

问题:既然说迭代器是一种智能指针,那么func对于普通的原始指针也应该是可用的,但是普通的原始指针不是对象,并不不具备value_type内嵌类型的定义,解决之道就是使用偏特化技术(partial specialization)。

模板特化

C++模板的分两种:偏特化和全特化(所谓偏特化是指部分特化)。

特化(或者说全特化,specialized)不过是一个花哨的术语,意思是形参不再为形参,它们已经有了确定的值;而偏特化(partial specialization)的意思是提供另一份template的定义,其本身仍然是一个template,或者说针对template参数更进一步的条件限制所设计出来的一个特化版本。

#include <iostream>
using namespace std;

// traits模板的定义
template<class I>
struct my_traits
{
    typedef typename I::value_type value_type;
};

// 针对T*的偏特化版本
template<class T>
struct my_traits<T*>
{
    typedef T value_type;
};

// 针对const T*的偏特化版本
template<class T>
struct my_traits<const T*>
{
    typedef T value_type;
};

// MyIter定义
template<class T>
struct MyIter
{
    typedef T value_type;
    T* ptr;
    MyIter(T* p=0) : ptr(p) {}
    T& operator*() const { return *ptr; }
};

// func函数模板,注意返回类型为typename my_traits<I>::value_type
template<class I>
typename my_traits<I>::value_type
func(I ite)
{
    return *ite;
}

int main(int argc, char **argv)
{
    MyIter<int> ite(new int(8));
    cout << func(ite) << endl;

    int *p = new int(1);
    const int *pc = new int(2);
    cout << func(p) << endl;
    cout << func(pc) << endl;

    return 0;
}
// 输出8 1 2

经过添加模板偏特化版本的定义之后,func对于原始指针也可以支持了。本文重点描述迭代器相关特性,所以关于特化的更多介绍,请自行搜索相关资料。

迭代器基本框架

按照约定,迭代器需要定义5个内嵌类型:iterator_categoryvalue_typedifference_typepointerreference

template <class Category,
          class T,
          class Distance = ptrdiff_t,
          class Pointer = T*,
          class Reference = T&>
struct iterator {
    typedef Category    iterator_category;
    typedef T           value_type;
    typedef Distance    difference_type;
    typedef Pointer     pointer;
    typedef Reference   reference;
};

也就是萃取出来模版参数的类型………………………

这些类型所表示的意义如下:

value type 用来表示迭代器所指对象的型别

difference type 用来表示两个迭代器之间的距离

reference引用类型

pointer指针类型

iterator_category 表明迭代器的类型

根据迭代器移动特性与施行动作,迭代器被分为五类:

  1. Input Iterator:这种迭代器所指对象,不允许外界改变,只读(read only);
  2. Output Iterator:唯写(write only);
  3. Forward Iterator:允许「写入型」算法(例如 replace())在此种迭代器所形成的区间上做读写动作;
  4. Bidirectional Iterator:可双向移动。某些算法需要逆向走访某个迭代器区间(例如逆向拷贝某范围内的元素),就可以使用 Bidirectional Iterators
  5. Random Access Iterator:前四种迭代器都只供应一部份指标算术能力(前3

    种支持 operator++ ,第4种再加上 operator–-),第5种则涵盖所有指标算术能力,包括 p+n, p-n, p[n], p1-p2, p1.

几种迭代器之间的关系图:

iterator源码

#ifndef __SGI_STL_INTERNAL_ITERATOR_BASE_H
#define __SGI_STL_INTERNAL_ITERATOR_BASE_H

#include <concept_checks.h>

__STL_BEGIN_NAMESPACE

// 五种迭代器tag的定义
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 {};

// input_iterator 定义
template <class _Tp, class _Distance> struct input_iterator {
  // 类别为 input_iterator_tag
  typedef input_iterator_tag iterator_category;
  typedef _Tp                value_type;
  typedef _Distance          difference_type;
  typedef _Tp*               pointer;
  typedef _Tp&               reference;
};

// output_iterator 定义
struct output_iterator {
  // 类别为 output_iterator_tag
  typedef output_iterator_tag iterator_category;
  typedef void                value_type;
  typedef void                difference_type;
  typedef void                pointer;
  typedef void                reference;
};

template <class _Tp, class _Distance> struct forward_iterator {
  typedef forward_iterator_tag iterator_category;
  // ...
};

template <class _Tp, class _Distance> struct bidirectional_iterator {
  typedef bidirectional_iterator_tag iterator_category;
  // ...
};

template <class _Tp, class _Distance> struct random_access_iterator {
  typedef random_access_iterator_tag iterator_category;
  // ...
};

#ifdef __STL_USE_NAMESPACES
// iterator 定义
template <class _Category, class _Tp, class _Distance = ptrdiff_t,
          class _Pointer = _Tp*, class _Reference = _Tp&>
struct iterator {
  typedef _Category  iterator_category;
  typedef _Tp        value_type;
  typedef _Distance  difference_type;
  typedef _Pointer   pointer;
  typedef _Reference reference;
};
#endif /* __STL_USE_NAMESPACES */

// 偏特化
#ifdef __STL_CLASS_PARTIAL_SPECIALIZATION

// iterator_traits 模板
template <class _Iterator>
struct iterator_traits {
  typedef typename _Iterator::iterator_category iterator_category;
  typedef typename _Iterator::value_type        value_type;
  typedef typename _Iterator::difference_type   difference_type;
  typedef typename _Iterator::pointer           pointer;
  typedef typename _Iterator::reference         reference;
};

// iterator_traits 针对指针的特化版本
template <class _Tp>
struct iterator_traits<_Tp*> {
  typedef random_access_iterator_tag iterator_category;
  typedef _Tp                         value_type;
  typedef ptrdiff_t                   difference_type;
  typedef _Tp*                        pointer;
  typedef _Tp&                        reference;
};

// iterator_traits 针对const指针的特化版本
template <class _Tp>
struct iterator_traits<const _Tp*> {
  typedef random_access_iterator_tag iterator_category;
  typedef _Tp                         value_type;
  typedef ptrdiff_t                   difference_type;
  typedef const _Tp*                  pointer;
  typedef const _Tp&                  reference;
};

// 获取迭代器的类型 (返回一个该类型的对象)
template <class _Iter>
inline typename iterator_traits<_Iter>::iterator_category
__iterator_category(const _Iter&)
{
  typedef typename iterator_traits<_Iter>::iterator_category _Category;
  return _Category();
}

// 获取迭代器的 __distance_type
template <class _Iter>
inline typename iterator_traits<_Iter>::difference_type*
__distance_type(const _Iter&)
{
  return static_cast<typename iterator_traits<_Iter>::difference_type*>(0);
}

// 获取迭代器的 __value_type
template <class _Iter>
inline typename iterator_traits<_Iter>::value_type*
__value_type(const _Iter&)
{
  return static_cast<typename iterator_traits<_Iter>::value_type*>(0);
}

// __iterator_category 的const参数版本
template <class _Iter>
inline typename iterator_traits<_Iter>::iterator_category
iterator_category(const _Iter& __i) { return __iterator_category(__i); }

// __distance_type 的const参数版本
template <class _Iter>
inline typename iterator_traits<_Iter>::difference_type*
distance_type(const _Iter& __i) { return __distance_type(__i); }

// __value_type 的const参数版本
template <class _Iter>
inline typename iterator_traits<_Iter>::value_type*
value_type(const _Iter& __i) { return __value_type(__i); }

#define __ITERATOR_CATEGORY(__i) __iterator_category(__i)
#define __DISTANCE_TYPE(__i)     __distance_type(__i)
#define __VALUE_TYPE(__i)        __value_type(__i)

#else /* __STL_CLASS_PARTIAL_SPECIALIZATION */
// 如果不支持偏特化,那么就需要定义iterator_category的函数重载的形式了
// 这里略去了此部分源代码的解释,因为估计也只有{非主流}编译器才不支持偏特化吧

#endif /* __STL_CLASS_PARTIAL_SPECIALIZATION */

// 体验traits技术的威力,针对不同的迭代器类型定义不同的distance实现版本
// _InputIterator 版本
template <class _InputIterator, class _Distance>
inline void __distance(_InputIterator __first, _InputIterator __last,
                       _Distance& __n, input_iterator_tag)
{
  while (__first != __last) { ++__first; ++__n; }
}

// _RandomAccessIterator版本
template <class _RandomAccessIterator, class _Distance>
inline void __distance(_RandomAccessIterator __first,
                       _RandomAccessIterator __last,
                       _Distance& __n, random_access_iterator_tag)
{
  __STL_REQUIRES(_RandomAccessIterator, _RandomAccessIterator);
  __n += __last - __first;
}

// distance 接口
// 注意 _RandomAccessIterator 也是 _InputIterator
template <class _InputIterator, class _Distance>
inline void distance(_InputIterator __first,
                     _InputIterator __last, _Distance& __n)
{
  __STL_REQUIRES(_InputIterator, _InputIterator);
  // 通过 iterator_category 取得迭代器类型
  __distance(__first, __last, __n, iterator_category(__first));
}

#ifdef __STL_CLASS_PARTIAL_SPECIALIZATION
// 对_Distance进行了特化
template <class _InputIterator>
inline typename iterator_traits<_InputIterator>::difference_type
__distance(_InputIterator __first, _InputIterator __last, input_iterator_tag)
{
  typename iterator_traits<_InputIterator>::difference_type __n = 0;
  while (__first != __last) {
    ++__first; ++__n;
  }
  return __n;
}

template <class _RandomAccessIterator>
inline typename iterator_traits<_RandomAccessIterator>::difference_type
__distance(_RandomAccessIterator __first, _RandomAccessIterator __last,
           random_access_iterator_tag) {
  __STL_REQUIRES(_RandomAccessIterator, _RandomAccessIterator);
  return __last - __first;
}

template <class _InputIterator>
inline typename iterator_traits<_InputIterator>::difference_type
distance(_InputIterator __first, _InputIterator __last) {
  typedef typename iterator_traits<_InputIterator>::iterator_category
    _Category;
  __STL_REQUIRES(_InputIterator, _InputIterator);
  return __distance(__first, __last, _Category());
}

#endif /* __STL_CLASS_PARTIAL_SPECIALIZATION */

// 体验traits技术的威力,针对不同的迭代器类型定义不同的advance实现版本
// _InputIterator 版本
template <class _InputIter, class _Distance>
inline void __advance(_InputIter& __i, _Distance __n, input_iterator_tag) {
  while (__n--) ++__i;
}

#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)
#pragma set woff 1183
#endif

// _BidirectionalIterator 之前前进与后退
template <class _BidirectionalIterator, class _Distance>
inline void __advance(_BidirectionalIterator& __i, _Distance __n,
                      bidirectional_iterator_tag) {
  __STL_REQUIRES(_BidirectionalIterator, _BidirectionalIterator);
  if (__n >= 0)
    while (__n--) ++__i;
  else
    while (__n++) --__i;
}

#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)
#pragma reset woff 1183
#endif

// _RandomAccessIterator版本
template <class _RandomAccessIterator, class _Distance>
inline void __advance(_RandomAccessIterator& __i, _Distance __n,
                      random_access_iterator_tag) {
  __STL_REQUIRES(_RandomAccessIterator, _RandomAccessIterator);
  __i += __n;
}

// advance 接口
template <class _InputIterator, class _Distance>
inline void advance(_InputIterator& __i, _Distance __n) {
  __STL_REQUIRES(_InputIterator, _InputIterator);
  __advance(__i, __n, iterator_category(__i));
}

__STL_END_NAMESPACE

#endif /* __SGI_STL_INTERNAL_ITERATOR_BASE_H */

代码中有distanceadvance两个函数,通过traits技术自动使用最佳的实现函数。

__type_traits

除了iterator_traits采用了traits技术外,还有一个叫做__type_traits的东西.

// 模拟true和false定义的两个空类型
struct __true_type {
};

struct __false_type {
};

template <class _Tp>
struct __type_traits {
   typedef __true_type     this_dummy_member_must_be_first;
   // 默认都是返回__false_type
   // 无意义的构造函数
   typedef __false_type    has_trivial_default_constructor;
   // 无意义的复制构造函数
   typedef __false_type    has_trivial_copy_constructor;
   // 无意义的赋值操作符
   typedef __false_type    has_trivial_assignment_operator;
   // 无意义的析构函数
   typedef __false_type    has_trivial_destructor;
   // 是否是POD类型
   typedef __false_type    is_POD_type;
};

// #define __STL_TEMPLATE_NULL template<>
// 这里定义的都是全特化版本
__STL_TEMPLATE_NULL struct __type_traits<char> {
   typedef __true_type    has_trivial_default_constructor;
   typedef __true_type    has_trivial_copy_constructor;
   typedef __true_type    has_trivial_assignment_operator;
   typedef __true_type    has_trivial_destructor;
   typedef __true_type    is_POD_type;
};
// ...

// 用于判断一个函数是否是整数类型
template <class _Tp> struct _Is_integer {
  // 默认不是整数类型
  typedef __false_type _Integral;
};

// 全特化版本
__STL_TEMPLATE_NULL struct _Is_integer<char> {
  typedef __true_type _Integral;
};

迭代器设计模式

迭代器模式是GoF提出的23中设计模式之一,**迭代器模式提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部表示。就如刚接触map/set等关联容器的时候,我们能够通过迭代器访问所有容器元素,却不知道容器是用红黑树实现的一样。

迭代器模式的类图结构如下:

时间: 2024-10-14 14:58:06

STL--迭代器--原理与实践的相关文章

有符号数和无符号数------c++程序设计原理与实践(进阶篇)

有符号数与无符号数的程序设计原则: 当需要表示数值时,使用有符号数(如 int). 当需要表示位集合时,使用无符号数(如unsigned int). 有符号数和无符号数混合运算有可能会带来灾难性的后果.例如: vector<int> v; for(int i=0;i<v.size();++i)cout<<v[i]<<'\n'; 易实现版本: unsigned char max=160; //非常大 for(signed char i=0;i<max;i++)

Apache Mahout之协同过滤原理与实践

Apache Mahout之协同过滤原理与实践 读书时期,选课是令人怀念的,因为自由,学生可以挑选自己喜爱的课程和老师!然而,过程并不是很美好,"系统繁忙,稍后重试!"屡有发生,于是大伙开心地约定今夜不战不休.西门的七彩路,和网吧名一样,我们从门口路过,进的却是右旁的可媛.这里网页同样坚持"系统繁忙,稍后重试!"!去的人多了,也就组了局.痛并快乐着应该如此!那以后,我们这堆人中出了一批又一批的高手,操作极限,走位妖娆,那都不是事儿! 戏后,一场深思悄然浮现:如果系统

分布式开放消息系统(RocketMQ)的原理与实践

分布式消息系统作为实现分布式系统可扩展.可伸缩性的关键组件,需要具有高吞吐量.高可用等特点.而谈到消息系统的设计,就回避不了两个问题: 消息的顺序问题 消息的重复问题 RocketMQ作为阿里开源的一款高性能.高吞吐量的消息中间件,它是怎样来解决这两个问题的?RocketMQ 有哪些关键特性?其实现原理是怎样的? 关键特性以及其实现原理 一.顺序消息 消息有序指的是可以按照消息的发送顺序来消费.例如:一笔订单产生了 3 条消息,分别是订单创建.订单付款.订单完成.消费时,要按照顺序依次消费才有意

Atitit 表达式原理 语法分析&#160;原理与实践 解析java的dsl &#160;递归下降是现阶段主流的语法分析方法

Atitit 表达式原理 语法分析 原理与实践 解析java的dsl  递归下降是现阶段主流的语法分析方法 于是我们可以把上面的语法改写成如下形式:1 合并前缀1 语法分析有自上而下和自下而上两种分析方法2 递归下降是现阶段主流的语法分析方法,2 于是我们可以把上面的语法改写成如下形式: 1)       Operator="+" | "-" | "*" | "/" 2)       Expression=<数字>

《从PAXOS到ZOOKEEPER分布式一致性原理与实践》pdf

下载地址:网盘下载 内容简介  · · · · · · <Paxos到Zookeeper:分布式一致性原理与实践>从分布式一致性的理论出发,向读者简要介绍几种典型的分布式一致性协议,以及解决分布式一致性问题的思路,其中重点讲解了Paxos和ZAB协议.同时,本书深入介绍了分布式一致性问题的工业解决方案--ZooKeeper,并着重向读者展示这一分布式协调框架的使用方法.内部实现及运维技巧,旨在帮助读者全面了解ZooKeeper,并更好地使用和运维ZooKeeper.全书共8章,分为五部分:第一

嵌入式实时操作系统μCOS原理与实践任务控制与时间的解析

/***********************************************************************************************************                                                uC/OS-II*                                          The Real-Time Kernel  RTOS* ***************

《数字图像处理原理与实践(MATLAB版)》一书之代码Part9

本文系<数字图像处理原理与实践(MATLAB版)>一书之代码系列的Part9,辑录该书第431至第438页之代码,供有需要读者下载研究使用.至此全书代码发布已经接近尾声,希望这些源码能够对有需要的读者有所帮助.代码执行结果请参见原书配图,建议下载代码前阅读下文: 关于<数字图像处理原理与实践(MATLAB版)>一书代码发布的说明 http://blog.csdn.net/baimafujinji/article/details/40987807 首先给出的是原书P438所列之程序源

《数字图像处理原理与实践(MATLAB版)》一书之代码Part8

本文系<数字图像处理原理与实践(MATLAB版)>一书之代码系列的Part8,辑录该书第375至第415页之代码,供有需要读者下载研究使用.至此全书代码发布已经接近尾声,希望这些源码能够对有需要的读者有所帮助.代码执行结果请参见原书配图,建议下载代码前阅读下文: 关于<数字图像处理原理与实践(MATLAB版)>一书代码发布的说明 http://blog.csdn.net/baimafujinji/article/details/40987807 P385-1 function y

20145309《网络对抗技术》免杀原理与实践

20145309<网络对抗技术>免杀原理与实践 1.基础问题回答 (1)杀软是如何检测出恶意代码的? 根据特征来检测:对已存在的流行代码特征的提取与比对根据行为来检测:是否有更改注册表行为.是否有设置自启动.是否有修改权限等等 (2)免杀是做什么? 使用一些方法使得恶意程序不被杀软和防火墙发现,避免被查杀. (3)免杀的基本方法有哪些? 加壳:就是相当于把你的后门代码封装起来,但是现在大部分公开的壳都能被杀毒软件查出来,所以加这些壳还不如不加:加花指令:就是加一段垃圾代码,但是并不影响程序的正

20145331魏澍琛《网络对抗》——免杀原理与实践

20145331魏澍琛<网络对抗>--免杀原理与实践 问题回答 1.杀软是如何检测出恶意代码的? 一个是基于特征码的检测,第二个是启发式恶意软件检测,最后是基于行为的恶意软件检测 2.免杀是做什么? 让病毒不被杀毒软件kill掉 3.免杀的基本方法有哪些? a)可以用这次实验所涉及的改变特征码 b)加壳:就是相当于把你的后门代码封装起来,但是现在大部分公开的壳都能被杀毒软件查出来,效果其实不好 实践过程 一.使用msf生成后门程序的检测 1.用上节课所讲的msf生成一个后门 2.到相应网站上查