STL源码阅读-iterator

本文详细解析C++中迭代器与智能指针auto_ptr的实现原理,包括输入迭代器、输出迭代器、前向迭代器、双向迭代器和随机访问迭代器的概念,以及auto_ptr的独占控制权转移机制。

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

侯捷的这一章写的是iterators与traits编程技法,之前就是对于traits这个技法不是很懂,花了一段时间去了解,所以看这一节的时候,主要是关注iterator的实现技术了。

迭按照设计模式给的iterator的定义,迭代器提供一种方法,使之能够依序巡防某个聚合物(容器)所含的各个元素,而又无需暴露该聚合物内部的表达方式。 STL将数据容器(container) 与算法(algorithm)分开,彼此设计独立,最后通过iterator实现两者的胶合。

1.auto_ptr智能指针

在STL iterator之前,先看一下c++自带的auto_ptr,源码如下。

template<class _Tp1> struct auto_ptr_ref {
  _Tp1* _M_ptr;
  auto_ptr_ref(_Tp1* __p) : _M_ptr(__p) {}
};

template <class _Tp> class auto_ptr {
private:
  _Tp* _M_ptr;

public:
  typedef _Tp element_type;

  explicit auto_ptr(_Tp* __p = 0) __STL_NOTHROW : _M_ptr(__p) {}
  auto_ptr(auto_ptr& __a) __STL_NOTHROW : _M_ptr(__a.release()) {}

#ifdef __STL_MEMBER_TEMPLATES
  template <class _Tp1> auto_ptr(auto_ptr<_Tp1>& __a) __STL_NOTHROW
    : _M_ptr(__a.release()) {}
#endif /* __STL_MEMBER_TEMPLATES */

  auto_ptr& operator=(auto_ptr& __a) __STL_NOTHROW {
    if (&__a != this) {
      delete _M_ptr;
      _M_ptr = __a.release();
    }
    return *this;
  }

#ifdef __STL_MEMBER_TEMPLATES
  template <class _Tp1>
  auto_ptr& operator=(auto_ptr<_Tp1>& __a) __STL_NOTHROW {
    if (__a.get() != this->get()) {
      delete _M_ptr;
      _M_ptr = __a.release();//首先释放__a的控制权,然后赋值
    }
    return *this;
  }
#endif /* __STL_MEMBER_TEMPLATES */

  // Note: The C++ standard says there is supposed to be an empty throw
  // specification here, but omitting it is standard conforming.  Its 
  // presence can be detected only if _Tp::~_Tp() throws, but (17.4.3.6/2)
  // this is prohibited.
  ~auto_ptr() { delete _M_ptr; }

  _Tp& operator*() const __STL_NOTHROW {
    return *_M_ptr;
  }
  _Tp* operator->() const __STL_NOTHROW {
    return _M_ptr;
  }
  _Tp* get() const __STL_NOTHROW {
    return _M_ptr;
  }
  _Tp* release() __STL_NOTHROW {
    _Tp* __tmp = _M_ptr;
    _M_ptr = 0;
    return __tmp;
  }
  void reset(_Tp* __p = 0) __STL_NOTHROW {
    if (__p != _M_ptr) {
      delete _M_ptr;
      _M_ptr = __p;
    }
  }

  // According to the C++ standard, these conversions are required.  Most
  // present-day compilers, however, do not enforce that requirement---and, 
  // in fact, most present-day compilers do not support the language 
  // features that these conversions rely on.
  
#if defined(__SGI_STL_USE_AUTO_PTR_CONVERSIONS) && \
    defined(__STL_MEMBER_TEMPLATES)

public:
  auto_ptr(auto_ptr_ref<_Tp> __ref) __STL_NOTHROW
    : _M_ptr(__ref._M_ptr) {}

  auto_ptr& operator=(auto_ptr_ref<_Tp> __ref) __STL_NOTHROW {
    if (__ref._M_ptr != this->get()) {
      delete _M_ptr;
      _M_ptr = __ref._M_ptr;
    }
    return *this;
  }

  template <class _Tp1> operator auto_ptr_ref<_Tp1>() __STL_NOTHROW 
    { return auto_ptr_ref<_Tp1>(this->release()); }
  template <class _Tp1> operator auto_ptr<_Tp1>() __STL_NOTHROW
    { return auto_ptr<_Tp1>(this->release()); }

#endif /* auto ptr conversions && member templates */
};

可以看到,auto_ptr在构造的时候会获得对象的控制权,同时这种控制是独占,也就是说如果存在赋值的情况,那么会首先释放控制权,然后再移交控制权。


2.Iterator

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

STL里面对于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;
};
这个template里面,我们需要引入的参数只有两个,_category和_Tp,为了维持统一的traits接口,自己在定义iterator的时候,最好是继承这个iterator,这样就能够比较好的兼容STL的其他函数和容器。

三个版本的iterator_traits技术,分别提取T、T*、const T的属性。

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;
};
//针对原生指针实现的偏特化
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;
};
//针对原生const pointer的偏特化
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;
};


这个函数能够返回方便的返回某个迭代器的类型(category)

template <class _Iter>
inline typename iterator_traits<_Iter>::iterator_category
__iterator_category(const _Iter&)
{
  typedef typename iterator_traits<_Iter>::iterator_category _Category; 
  return _Category();//返回一个<span style="font-family: Arial, Helvetica, sans-serif;">iterator_traits<_Iter>::iterator_category对象,用于实现traits技术</span>
}

这个函数能够很容易的获得某个迭代器的distance类型,distance是指两个指针之间的距离。

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& __i) { return __value_type(__i); }
下面的__value_type函数和__distance_type函数返回的都是指针,很好奇这样做的原因,因为这几个函数一直没有被使用到,所以目前还不知道为什么一定要返回*。


然后就是advance函数了,advance函数主要是移动指针,有三个类型,主要是针对双向iterator、单向iterator以及random iterator。

template <class _InputIter, class _Distance>
inline void __advance(_InputIter& __i, _Distance __n, input_iterator_tag) {
  while (__n--) ++__i;
}
双向iterator:

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;
}
random iterator:

template <class _RandomAccessIterator, class _Distance>
inline void __advance(_RandomAccessIterator& __i, _Distance __n, 
                      random_access_iterator_tag) {
  __STL_REQUIRES(_RandomAccessIterator, _RandomAccessIterator);
  __i += __n;
}

最后,进行统一的封装,利用traits技术,实现性能的优化。

template <class _InputIterator, class _Distance>
inline void advance(_InputIterator& __i, _Distance __n) {
  __STL_REQUIRES(_InputIterator, _InputIterator);
  __advance(__i, __n, iterator_category(__i));
}

侯捷这部分的内容主要是讲traits技术,源代码里面我看的主要是iterator_base里面的代码,还没有看reverse_iterator各种iterator,看到了再接着补充



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值