C++ 迭代器, iterator

本文详细解析了迭代器在STL中的角色、分类及其在算法使用中的作用,包括不同迭代器的实现原理及特性,并展示了如何通过traits编程技巧获取迭代器的属性,以提高代码的灵活性和效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转载:http://hi.baidu.com/xmuwubo/item/819749f76ba88617d6ff8c7a

各类iterator 迭代器详解

STL设计的精髓在于,把容器(Containers)和算法(Algorithms)分开,彼此独立设计,最后再用迭代器(Iterator)把他们粘合在一起。可见迭代器在STL中的重要程度。迭代器已经作为一种设计思想被记录与《设计模式》中,它的意图在于“提供一种方法顺序访问一个聚合对象中的各个元素,而又不需暴露该对象的内部表示”。

迭代器的作用其实相当于一个智能指针,它指向容器内部的数据,可以通过operator *操作符来解指针获得数据的值,也可以通过operator ->操作符来获取数据的指针,还能够重载++,--等运算符来移动指针。

迭代器的分类

迭代器大致可以分为以下几种:

1、Input Interator :只允许作为输入,也就是只读(Read Only)
2、Output Interator :只允许作为输出,也就是只写(Write Only)
3、Forward Interator :允许读写,但只能做前向移动
4、Bidirectional Interator :允许读写,可以做双向移动
5、Random Access Interator :允许读写,可以任意移动

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 {};

实现原理

下面以List为例说明迭代器的原理

// List节点的定义 
template <class T> 
struct __list_node { 
typedef void* void_pointer; 
void_pointer next; 
void_pointer prev; 
T data; 
};

// List迭代器的定义 
template<class T, class Ref, class Ptr> 
struct __list_iterator { 
// 这三个typedef是为了简化后面的代码书写 
typedef __list_iterator<T, T&, T*>             iterator; 
typedef __list_iterator<T, const T&, const T*> const_iterator; 
typedef __list_iterator<T, Ref, Ptr>           self;

typedef bidirectional_iterator_tag iterator_category;     // 迭代器类型属于bidirectional iterator 
typedef T value_type;     // 值类型 
typedef Ptr pointer;      // 指针类型 
typedef Ref reference;    // 引用类型 
typedef __list_node<T>* link_type;    // 节点指针类型 
typedef size_t size_type; 
typedef ptrdiff_t difference_type;

link_type node;   // 迭代器当前所指的节点

// 三种构造函数 
__list_iterator(link_type x) : node(x) {} 
__list_iterator() {} 
__list_iterator(const iterator& x) : node(x.node) {}

// ==和!=操作符重载 
bool operator==(const self& x) const { return node == x.node; } 
bool operator!=(const self& x) const { return node != x.node; } 
   
// *操作符,汲取所指节点中的数据 
reference operator*() const { return (*node).data; } 
// ->操作符,汲取所指节点中数据的地址 
pointer operator->() const { return &(operator*()); 
// 前置++操作符,指向下一个节点 
self& operator++() { 
    node = (link_type)((*node).next); 
    return *this; 

// 后置++操作符,指向下一个节点 
self operator++(int) { 
    self tmp = *this; 
    ++*this; 
    return tmp; 

// 前置--操作符,指向前一个节点 
self& operator--() { 
    node = (link_type)((*node).prev); 
    return *this; 

// 后置--操作符,指向前一个节点 
self operator--(int) { 
    self tmp = *this; 
    --*this; 
    return tmp; 

};

template <class T, class Alloc = alloc> 
class list { 
... 
...

public: 
typedef __list_iterator<T, T&, T*>             iterator;          // 注意iterator所用的就是__list_iterator 
typedef __list_iterator<T, const T&, const T*> const_iterator;

... 
...

protected: 
link_type node;   // 头节点,该List其实是一个带头节点的双向循环链表

public: 
list() { empty_initialize(); }

iterator begin() { return (link_type)((*node).next); }        // 返回头节点的下一个节点,即第一个节点的iterator 
const_iterator begin() const { return (link_type)((*node).next); } 
iterator end() { return node; }               // 返回头节点的iterator,其实就是返回链表的结尾 
const_iterator end() const { return node; } 
   
... 
... 
}
如果我们对List容器使用find算法,这一过程中会发生什么?
int a[] = {1,2,3,4,5};
list<int> l(a, a+5);
list<int>::iterator it = find(l.begin(), l.end(), 3);
cout << *it << end;

先看看find函数的定义

template <class InputIterator, class T> 
InputIterator find(InputIterator first, InputIterator last, const T& value) { 
while (first != last && *first != value) ++first; 
return first; 
}
我们所调用的find函数的特化版本其实是:
find<__list_iterator<int, int&, int*>, int>(__list_iterator<int, int&, int*> first, __list_iterator<int, int&, int*> last, const int& value)
从而find函数中所用到的!=、*、++等操作符都作用在__list_iterator<int, int&, int*>的身上,这正是泛型的作用所在。

STL中迭代器的各种特性

还记得我在《STL源码剖析学习笔记2——神奇的__type_traits》中所提到的traits编程技巧么?在STL的迭代器中同样用到了这种技巧,因为STL的迭代器在使用的时候需要了解各种迭代器的特性。主要特性包含以下几种:
1、iterator_category:表示迭代器所属的类型
2、value_type:表示迭代器所指数据的类型
3、difference_type:表示两个迭代器之间的距离类型
4、pointer:表示迭代器所指数据的指针类型
5、reference:表示迭代器所指数据的引用类型

通常迭代器的几种特性被放在iterator_traits中。

// 对所有Iterator的泛化 
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; 
};

// 对指针类型的偏特化(Partial Spetialization) 
template <class T> 
struct iterator_traits<T*> { 
typedef random_access_iterator_tag iterator_category;     // 指针类型是可以随机访问的 
typedef T                          value_type;            // 值类型 
typedef ptrdiff_t                  difference_type;       // 指针类型之间的距离一定是整型(ptrdiff_t被定义为int型) 
typedef T*                         pointer; 
typedef T&                         reference; 
}; 
template <class T> 
struct iterator_traits<const T*> {      // 同上,只不过这里是常量指针 
typedef random_access_iterator_tag iterator_category; 
typedef T                          value_type; 
typedef ptrdiff_t                  difference_type; 
typedef const T*                   pointer; 
typedef const T&                   reference; 
};
各种不同的迭代器的特性定义如下:

// input iterator的属性 
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; 
}; 
// output iterator的属性 
struct output_iterator { 
typedef output_iterator_tag iterator_category; 
typedef void                value_type; 
typedef void                difference_type; 
typedef void                pointer; 
typedef void                reference; 
}; 
// forward iterator的属性 
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; 
}; 
// bidirectional iterator的属性 
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; 
}; 
// random access iterator的属性 
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_traits就能得到相应interator的各种特性,这样可以让程序更灵活,也能提高效率。
下面几个例子是为了说明iterator_traits在STL中的使用
eg1. count模板函数,它的返回值必须使用difference_type

template <class InputIterator, class T> 
typename iterator_traits<InputIterator>::difference_type 
count(InputIterator first, InputIterator last, const T& value) { 
typename iterator_traits<InputIterator>::difference_type n = 0;   // 萃取迭代器的difference_type类型 
for ( ; first != last; ++first) 
    if (*first == value) 
      ++n; 
return n; 
}
eg2. advance模板函数,为了提高效率,必须针对不同类型的iterator重载不同的处理函数

template <class InputIterator, class Distance> 
inline void advance(InputIterator& i, Distance n) { 
__advance(i, n, iterator_category(i));    // 根据不同的类型调用不同的重载函数 
}

// iterator_category函数的定义 
template <class Iterator> 
inline typename iterator_traits<Iterator>::iterator_category 
iterator_category(const Iterator&) { 
typedef typename iterator_traits<Iterator>::iterator_category category;   // 其实就是返回Iterator的iterator_category类型 
return category(); 
}
再看__advance函数针对不同迭代器的三种版本,它们分别针对input iterator、forward iterator、Bidirectional iterator和Random access iterator四种不同的迭代器

// 针对input iterator和forward iterator的版本 
template <class InputIterator, class Distance> 
inline void __advance(InputIterator& i, Distance n, input_iterator_tag) { 
while (n--) ++i; // 只能单向移动 

// 针对Bidirectional iterator的版本 
template <class BidirectionalIterator, class Distance> 
inline void __advance(BidirectionalIterator& i, Distance n, 
                      bidirectional_iterator_tag) { 
if (n >= 0)           // 根据方向不同有不同的处理 
    while (n--) ++i; 
else 
    while (n++) --i; 

// 针对Random access iterator的版本 
template <class RandomAccessIterator, class Distance> 
inline void __advance(RandomAccessIterator& i, Distance n, 
                      random_access_iterator_tag) { 
i += n;   // 随机访问,提高效率 
}
总的来说,在STL中是由容器(container)来负责设计适当的迭代器(iterator),由迭代器(iterator)来负责设计适当的迭代器属性。正因为这一点才使得容器和算法可以完全分离开来,通过迭代器提供的接口来访问容器的内部元素。在这里我们又一次看到了traits编程技巧的强大功能,在很大程度上弥补了C++语言不是强类型语言的不足之处。


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值