STL源码剖析(3):迭代器(iterators)

来源:互联网 发布:top域名备案 编辑:程序博客网 时间:2024/04/30 09:34

  关于迭代器的基本介绍可以看我之前泛型编程的文章:
  STL的中心思想在于:将数据容器(containers)和算法(algorithms)分开,彼此独立设计,最后再以一帖粘合剂将它们撮合在一起。
  迭代器(iterator)是一种 smart pointer,关于智能指针可以看我之前的文章(智能指针)。
   迭代器是一种行为类似指针的对象,而指针的各种行为中最常见也最重要的便是内容提领(dereference)和成员访问(member access),因此,迭代器最重要的编程工作就是对 operator* 和 operator-> 进行重载(overloading)工作。
   相信用过STL容器的都知道,每一种STL容器都提供有专属迭代器。迭代器作为这么重要的东东,为什么独立成体,因为迭代器的操作严重依赖容器自身操作特性。
   这部分基本内容前面文章都有介绍,这里看下其代码:

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 {};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;};struct output_iterator {  typedef output_iterator_tag iterator_category;  typedef void                value_type;  typedef void                difference_type;  typedef void                pointer;  typedef void                reference;};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;};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;};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;};#ifdef __STL_USE_NAMESPACEStemplate <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;};#endif /* __STL_USE_NAMESPACES */#ifdef __STL_CLASS_PARTIAL_SPECIALIZATIONtemplate <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;};template <class T>struct iterator_traits<T*> {  typedef random_access_iterator_tag iterator_category;  typedef T                          value_type;  typedef ptrdiff_t                  difference_type;  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;};template <class Iterator>inline typename iterator_traits<Iterator>::iterator_categoryiterator_category(const Iterator&) {  typedef typename iterator_traits<Iterator>::iterator_category category;  return category();}template <class Iterator>inline typename iterator_traits<Iterator>::difference_type*distance_type(const Iterator&) {  return static_cast<typename iterator_traits<Iterator>::difference_type*>(0);}template <class Iterator>inline typename iterator_traits<Iterator>::value_type*value_type(const Iterator&) {  return static_cast<typename iterator_traits<Iterator>::value_type*>(0);}#else /* __STL_CLASS_PARTIAL_SPECIALIZATION */template <class T, class Distance> inline input_iterator_tag iterator_category(const input_iterator<T, Distance>&) {  return input_iterator_tag();}inline output_iterator_tag iterator_category(const output_iterator&) {  return output_iterator_tag();}template <class T, class Distance> inline forward_iterator_tagiterator_category(const forward_iterator<T, Distance>&) {  return forward_iterator_tag();}template <class T, class Distance> inline bidirectional_iterator_tagiterator_category(const bidirectional_iterator<T, Distance>&) {  return bidirectional_iterator_tag();}template <class T, class Distance> inline random_access_iterator_tagiterator_category(const random_access_iterator<T, Distance>&) {  return random_access_iterator_tag();}template <class T>inline random_access_iterator_tag iterator_category(const T*) {  return random_access_iterator_tag();}

  这里来看front-insert interator:Constructs a front-insert iterator that inserts new elements at the beginning of x.
  A front-insert interator is a special type of output iterator designed to allow algorithms that usually overwrite elements (such as copy) to instead insert new elements automatically at the beginning of the container.
  The type of x needs to have a push_front member function (such as the standard containers deque and list).
  Using the assignment operator on the returned iterator (either dereferenced or not), causes the container to expand by one element, which is initialized to the value assigned.
  The returned iterator supports all other typical operations of output iterators but have no effect: all values assigned are inserted at the beginning of the container.

template <class Container>  class front_insert_iterator :    public iterator<output_iterator_tag,void,void,void,void>{protected:  Container* container;public:  typedef Container container_type;  explicit front_insert_iterator (Container& x) : container(&x) {}  front_insert_iterator<Container>& operator= (typename Container::const_reference value)    { container->push_front(value); return *this; }  front_insert_iterator<Container>& operator* ()    { return *this; }  front_insert_iterator<Container>& operator++ ()    { return *this; }  front_insert_iterator<Container> operator++ (int)    { return *this; }};

  来看个例子:

// front_inserter example#include <iostream>     // std::cout#include <iterator>     // std::front_inserter#include <deque>        // std::deque#include <algorithm>    // std::copyint main () {  std::deque<int> foo,bar;  for (int i=1; i<=5; i++)  { foo.push_back(i); bar.push_back(i*10); }  std::copy (bar.begin(),bar.end(),std::front_inserter(foo));  std::cout << "foo contains:";  for ( std::deque<int>::iterator it = foo.begin(); it!= foo.end(); ++it )      std::cout << ' ' << *it;  std::cout << '\n';  return 0;}//Output:50 40 30 20 10 1 2 3 4 5

  上面的copy(),最终代码类似:

  for (Distance n = last - first; n > 0; --n, ++result, ++first)     *result = *first;  return result;

  如何定义一个iterator
  在定义自己的iterator时,你需要提供iterator traits。
  有两种方法;
  1.提供必要的iterator_traits的五种类型。
  2.提供iterator_traits结构体的特化。
  对于第一种方法,STL提供了一个基类iterator:

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

  当设计新的迭代器是,你可以继承他:

class MyIterator: public std::iterator <std::bidirectional_iterator_tag,type, ptrdiff_t, type*, type&> {...};

  第一个参数是the iterator category, 第二个参数是元素类型type,第三个是差值类型(difference type),第四个是指针类型(pointer type),第五个是引用类型(reference type),最后三个是可选的,它们默认的类型:ptrdif_f_t, type*, and type&。

总结:
   设计适当的型别是迭代器的责任,实际适当的迭代器则是容器的责任,算法完全可以独立于容器和迭代器之外自行发展,只要设计时以迭代器为对外接口就可以了。
   traits编程技法大量运用于STL实现中,它利用“内嵌类型”的编程技巧与编译器的参数推导功能,增强C++未能提供的关于型别认证方面的能力,弥补C++不为强类型语言的遗憾。

0 0