首页 > STL源码剖析 > STL笔记之迭代器

STL笔记之迭代器

迭代器(iterator)是STL里面很基础也很重要的一个东西,迭代器的traits技术设计的很棒(在上一篇文章《STL笔记之空间配置器》中提到destroy函数使用了traits技术来判断对象是否具有trivial destructor,然后通过重载自动选择合适的实现版本)。

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

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

1
2
3
4
5
6
7
8
9
10
11
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技术了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#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));
    cout << func(ite) << endl;
 
    return 0;
}
// 输出8

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#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对于原始指针也可以支持了。本文重点描述迭代器相关特性,所以关于特化的更多介绍,请自行搜索相关资料。

3. 迭代器基本框架
按照约定,迭代器需要定义5个内嵌类型:iterator_category、value_type、difference_type、pointer、reference

1
2
3
4
5
6
7
8
9
10
11
12
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

4. iterator源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
#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 */

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

5. __type_traits
除了iterator_traits采用了traits技术外,还有一个叫做__type_traits的东西,也就是文章开头提到的:上一篇文章《STL笔记之空间配置器》就用到了__type_traits。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// 模拟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;
};

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

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

参考
1. C++模板:究竟什么是特化?


觉得文章还不错?点击此处对作者进行打赏!


本文地址: 程序人生 >> STL笔记之迭代器
作者:代码疯子(Wins0n) 本站内容如无声明均属原创,转载请保留作者信息与原文链接,谢谢!


更多



  1. 2014年6月14日22:06 | #1

    膜拜大神 [em022]
    请教个问题,一直用C,对C++没深入学习过,有人说C++相对C的优势主要就是STL,想学习一下面向对象设计思想,该怎么入手?看经典教材?直接学习STL源码? [em018]

    [回复]

    代码疯子 回复:

    @geeksword, C++不是纯粹的面向对象编程语言,STL主要是泛型思维(不是OOP),看这个主要是了解一些底层的实现机制以及一些设计思维,这样STL用起来也会得心应手了。至于面向对象我觉得稍微了解一下就好了,不需要专门找什么书看,有兴趣可以了解下设计模式,当然现在大部分都是以Java这种语言来讲解的。STL不过是个库,C++还有Boost,现在C++ 11已经融入了非常多的新特性。

    [回复]

  1. 2014年6月20日21:15 | #1