stl源码剖析之vector,list,deque迭代器分析

一.模型
vector维护的是连续线性空间,当空间大小不足时,另辟一块更大的内存,将之前空间的所有元素移至新空间,并销毁释放原空间。stl中list是一个环状双向链表,它维护的不是连续空间,而是一个个的节点(__list_node),节点之间通过指针连接。deque维护的也是连续线性空间,不过不同于vector,它的空间是分段连续的,当空间大小不足时,deque可以另辟一块空间,并与原来的空间通过中控器链接起来。
具体模型:
vector的空间模型
vector

list的空间模型
list

deque的空间模型
这里写图片描述
二.迭代器
http://blog.youkuaiyun.com/u010772289/article/details/52430415 中讲述过迭代器有五种类型,分别为Input Iterator(只读),Output Iterator(只写),Forward Iterator(前向移动),Bidirectional Iterator(双向移动),Random Access Iterator(双向跳跃移动)
vector的迭代器是一个普通指针,普通指针支持双向跳跃移动,因此符合vector随机存取的特性。list的迭代器是必须具备前移后移的能力,即为Bidirectional Iterator,它不能选择普通的指针作为迭代器,需要自己另外定义迭代器类。deque维护的是分段连续空间,其迭代器支持双向随意移动,因此需要是Random Access Iterator,但它不能选择普通指针作为迭代器,因为deque的迭代器一旦到达缓冲区的边缘,它前进或后退时必须得跳跃到下一个或上一个缓冲区。
list的节点以及迭代器定义如下:

template <class T>
struct __list_node {
  typedef void* void_pointer;
  void_pointer next;
  void_pointer prev;
  T data;
};
template<class T, class Ref, class Ptr>
struct __list_iterator {
  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; }

#ifndef __SGI_STL_NO_ARROW_OPERATOR
  pointer operator->() const { return &(operator*()); }
#endif /* __SGI_STL_NO_ARROW_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;
  }
};

可以看出,list的是双向链表,其节点中定义了一个指向上一个节点的指针prev以及指向下一个节点的指针next。其迭代器类型(iterator_category)为bidirectional_iterator_tag(它是一个struct类,定义在stl_iterator.h中,表示可双向移动的迭代器类型,参考http://blog.youkuaiyun.com/u010772289/article/details/52430415),另外为了支持list的迭代器前向/后向移动的特性,需要重载++,–等运算符。

deque的迭代器定义如下:

#ifndef __STL_NON_TYPE_TMPL_PARAM_BUG
template <class T, class Ref, class Ptr, size_t BufSiz>
struct __deque_iterator {   
  typedef __deque_iterator<T, T&, T*, BufSiz>             iterator;     //iterator
  typedef __deque_iterator<T, const T&, const T*, BufSiz> const_iterator;//const_iterator
  static size_t buffer_size() {return __deque_buf_size(BufSiz, sizeof(T)); }  //缓冲区大小
#else /* __STL_NON_TYPE_TMPL_PARAM_BUG */
template <class T, class Ref, class Ptr>
struct __deque_iterator {
  typedef __deque_iterator<T, T&, T*>             iterator;
  typedef __deque_iterator<T, const T&, const T*> const_iterator;
  static size_t buffer_size() {return __deque_buf_size(0, sizeof(T)); }
#endif

  typedef random_access_iterator_tag iterator_category;//定义iterator_category,供iterator_traits用    为何此文件未包含random_access_iterator_tag所在头文件"stl_iterator"????
  typedef T value_type;     
  typedef Ptr pointer;
  typedef Ref reference;
  typedef size_t size_type;
  typedef ptrdiff_t difference_type;
  typedef T** map_pointer;   //指向中控器的指针

  typedef __deque_iterator self;

  T* cur;   //缓冲区中当前指针
  T* first; //缓冲区头指针
  T* last;  //缓冲区尾指针
  map_pointer node;

  __deque_iterator(T* x, map_pointer y)  //__deque_iterator构造函数
    : cur(x), first(*y), last(*y + buffer_size()), node(y) {}   //缓冲区当前指针,头指针,尾指针
  __deque_iterator() : cur(0), first(0), last(0), node(0) {}
  __deque_iterator(const iterator& x)   //拷贝构造函数
    : cur(x.cur), first(x.first), last(x.last), node(x.node) {}

  reference operator*() const { return *cur; }    //const成员函数
#ifndef __SGI_STL_NO_ARROW_OPERATOR
  pointer operator->() const { return &(operator*()); }
#endif /* __SGI_STL_NO_ARROW_OPERATOR */

  difference_type operator-(const self& x) const {
    return difference_type(buffer_size()) * (node - x.node - 1) +
      (cur - first) + (x.last - x.cur);
  }

  self& operator++() {
    ++cur;
    if (cur == last) {
      set_node(node + 1);
      cur = first;
    }
    return *this; 
  }
  self operator++(int)  {
    self tmp = *this;
    ++*this;
    return tmp;
  }

  self& operator--() {
    if (cur == first) {
      set_node(node - 1);
      cur = last;
    }
    --cur;
    return *this;
  }
  self operator--(int) {
    self tmp = *this;
    --*this;
    return tmp;
  }

  self& operator+=(difference_type n) {
    difference_type offset = n + (cur - first);
    if (offset >= 0 && offset < difference_type(buffer_size()))
      cur += n;
    else {
      difference_type node_offset =
        offset > 0 ? offset / difference_type(buffer_size())
                   : -difference_type((-offset - 1) / buffer_size()) - 1;
      set_node(node + node_offset);
      cur = first + (offset - node_offset * difference_type(buffer_size()));
    }
    return *this;
  }

  self operator+(difference_type n) const {
    self tmp = *this;
    return tmp += n;
  }

  self& operator-=(difference_type n) { return *this += -n; }

  self operator-(difference_type n) const {
    self tmp = *this;
    return tmp -= n;
  }

  reference operator[](difference_type n) const { return *(*this + n); }

  bool operator==(const self& x) const { return cur == x.cur; }
  bool operator!=(const self& x) const { return !(*this == x); }
  bool operator<(const self& x) const {
    return (node == x.node) ? (cur < x.cur) : (node < x.node);
  }

  void set_node(map_pointer new_node) {   //切换至正确的节点,即缓冲区
    node = new_node;
    first = *new_node;
    last = first + difference_type(buffer_size());
  }
};

因为deque的迭代器支持双向随意移动,因而重载了++ , – ,+, - 等运算符。当迭代器移动超出当前缓冲区范围时,需要切换至其它节点(函数set_node)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值