让你的容器兼容STL
大家知道,STL最最主要,也是最最常用的部分就是泛型容器和范型算法。而联系起这两大部分的,就是iterator(迭代器)。
迭代器大体分为这么几类(级别从低到高)
只读迭代器input_iterator
只写迭代器output_iterator
forward_iterator,这个其实是允许写入型算法在其所形成的区间上做读写操作
双向移动可读写bidirectional_iterator
随机访问迭代器random_access_iterator
很明了,各种不同的迭代器其实规定了其宿主所具有的能力。 比方说,forward_iterator只允许但方向遍历,像单项链表之类的数据结构,就只能拥有此类迭代器。一些需要双向操作或反向操作的算法,就不支持此类容器了。
而最高级别的随机访问迭代器,则不但允许双向读写,而且支持随即访问,也就是像操作内置数组那样。比如std::vector就属于随即访问型容器。
我记得侯叔叔的《STL源码抛析》里面说过,使用STL分为三个境界,第一层:使用;第二层:了解;第三次:扩展STL。
那么我们现在先窥探一下第三层的大门,至少让自己的类型和STL兼容。
那前面发过的Array动态数组做例子吧,其实这个类就是个简易的vector,根本够不上对STL的扩展,只是向这个境界迈那么一小步而已。
其实,要让自己的容器兼容STL的反省算法,就必须要让这些算法知道你的容器是那种类型的,换句话说,要让它们知道你的容器拥有哪种类型的迭代器。
STL为我们定义了上述集中迭代器类型
2 { // identifying tag for input iterators
3 };
4
5 struct output_iterator_tag
6 { // identifying tag for output iterators
7 };
8
9 struct forward_iterator_tag
10 : public input_iterator_tag
11 { // identifying tag for forward iterators
12 };
13
14 struct bidirectional_iterator_tag
15 : public forward_iterator_tag
16 { // identifying tag for bidirectional iterators
17 };
18
19 struct random_access_iterator_tag
20 : public bidirectional_iterator_tag
21 { // identifying tag for random-access iterators
22 };
其实这些类型什么也不做,只是一个标识(identity),告诉别人能做什么,怎么做。
另外,还需要定义下面几个类型,这些都是什么我就不具体说了,大家有兴趣可以看STL源代吗或侯叔叔的书。不过要看源代码最好看STLPort的,比较清晰。
2 typedef typename allocator<T>::difference_type difference_type;
3 typedef typename allocator<T>::const_pointer pointer;
4 typedef typename allocator<T>::const_reference reference;
好了,让我们来修改Array的迭代器,让它兼容STL
1 struct Iterator
3 {
4 typedef random_access_iterator_tag iterator_category;
5 typedef T value_type;
6 typedef typename allocator<T>::difference_type difference_type;
7 typedef typename allocator<T>::const_pointer pointer;
8 typedef typename allocator<T>::const_reference reference;
9
10 Iterator(T* ptr):m_ptr(ptr){}
11
12 reference operator*()
13 {
14 return (*m_ptr);
15 }
16
17 pointer operator->()
18 {
19 return (&**this);
20 }
21
22 Iterator& operator++()
23 {
24 ++m_ptr;
25 return *this;
26 }
27 Iterator operator++(int)
28 {
29 Iterator temp = *this;
30 ++(*this);
31 return temp;
32 }
33
34 Iterator& operator--()
35 {
36 --m_ptr;
37 return *this;
38 }
39 Iterator operator--(int)
40 {
41 Iterator temp = *this;
42 --(*this);
43 return temp;
44 }
45
46 bool operator!=(const Iterator &it)
47 {
48 return m_ptr != it.m_ptr;
49 }
50
51 bool operator==(const Iterator &it)
52 {
53 return m_ptr == it.m_ptr;
54 }
55
56 bool operator<(const Iterator &it)
57 {
58 return m_ptr<it.m_ptr;
59 }
60
61 Iterator operator+(difference_type off) const
62 {
63 Iterator tmp = *this;
64 tmp.m_ptr+=off;
65 return tmp;
66 }
67
68
69
70 Iterator operator-(difference_type off)
71 {
72 Iterator tmp = *this;
73 tmp.m_ptr-=off;
74 return tmp;
75 }
76
77 difference_type operator-(const Iterator& it)
78 {
79 return m_ptr - it.m_ptr;
80 }
81
82
83 T* m_ptr;
84 };