STL 源码剖析 -- Iterator 迭代器全揭秘

1、iterator_tag

iterator_tag 标记了 iterator 的类型。

  ///  Marking input iterators.
  struct input_iterator_tag { };

  ///  Marking output iterators.
  struct output_iterator_tag { };

  /// Forward iterators support a superset of input iterator operations.
  struct forward_iterator_tag : public input_iterator_tag { };

  /// Bidirectional iterators support a superset of forward iterator
  /// operations.
  struct bidirectional_iterator_tag : public forward_iterator_tag { };

  /// Random-access iterators support a superset of bidirectional
  /// iterator operations.
  struct random_access_iterator_tag : public bidirectional_iterator_tag { };

2、iterator

每个 iterator 都必须提供以下 5 中数据类型

  • iterator_category
  • value_type
  • difference_type
  • pointer
  • reference
  template<typename _Category, typename _Tp, typename _Distance = ptrdiff_t,
           typename _Pointer = _Tp*, typename _Reference = _Tp&>
    struct _GLIBCXX17_DEPRECATED iterator
    {
      /// One of the @link iterator_tags tag types@endlink.
      typedef _Category  iterator_category;
      /// The type "pointed to" by the iterator.
      typedef _Tp        value_type;
      /// Distance between iterators is represented as this type.
      typedef _Distance  difference_type;
      /// This type represents a pointer-to-value_type.
      typedef _Pointer   pointer;
      /// This type represents a reference-to-value_type.
      typedef _Reference reference;
    };

3、iterator_traits

iterator_traits 是为了兼容原生指针(原生指针没有定义上述 5 中数据类型)

  template<typename _Iterator>
    struct __iterator_traits<_Iterator,
                 __void_t<typename _Iterator::iterator_category,
                      typename _Iterator::value_type,
                      typename _Iterator::difference_type,
                      typename _Iterator::pointer,
                      typename _Iterator::reference>>
    {
      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<typename _Iterator>
    struct iterator_traits
    : public __iterator_traits<_Iterator> { };

iterator_traits 使用偏特化的方法,对于原生指针,也定义了 Iterator 的 5 中数据类型。

  template<typename _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;
    };

  /// Partial specialization for const pointer types.
  template<typename _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;
    };

4、std::distance()/std::advance()

4.1、std::distance()

std::distance() 计算 first 到 last 的距离。不同的 iterator_tag 支持的操作不同,计算方法也不同。

  template<typename _InputIterator>
    _GLIBCXX_NODISCARD
    inline _GLIBCXX17_CONSTEXPR
    typename iterator_traits<_InputIterator>::difference_type
    distance(_InputIterator __first, _InputIterator __last)
    {
      // concept requirements -- taken care of in __distance
      return std::__distance(__first, __last,
                 std::__iterator_category(__first));
    }

input_iterator_tag 每次只能移动一步,循环直到 first == last,返回距离。

  template<typename _InputIterator>
    inline _GLIBCXX14_CONSTEXPR
    typename iterator_traits<_InputIterator>::difference_type
    __distance(_InputIterator __first, _InputIterator __last,
               input_iterator_tag)
    {
      // concept requirements
      __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>)

      typename iterator_traits<_InputIterator>::difference_type __n = 0;
      while (__first != __last)
    {
      ++__first;
      ++__n;
    }
      return __n;
    }

如果是 random_access_iterator_tag,直接 last - first 返回结果

  template<typename _RandomAccessIterator>
    inline _GLIBCXX14_CONSTEXPR
    typename iterator_traits<_RandomAccessIterator>::difference_type
    __distance(_RandomAccessIterator __first, _RandomAccessIterator __last,
               random_access_iterator_tag)
    {
      // concept requirements
      __glibcxx_function_requires(_RandomAccessIteratorConcept<
                  _RandomAccessIterator>)
      return __last - __first;
    }

output_iterator_tag 是不支持 std::distance() 计算

template<typename _OutputIterator>
    void
    __distance(_OutputIterator, _OutputIterator, output_iterator_tag) = delete;

4.2、std::advance()

std::advance() 将 first 移动 n 个位置。

  template<typename _InputIterator, typename _Distance>
    inline _GLIBCXX17_CONSTEXPR void
    advance(_InputIterator& __i, _Distance __n)
    {
      // concept requirements -- taken care of in __advance
      typename iterator_traits<_InputIterator>::difference_type __d = __n;
      std::__advance(__i, __d, std::__iterator_category(__i));
    }

如果是 input_iterator_tag,仅仅支持正向移动,每次移动一步。

  template<typename _InputIterator, typename _Distance>
    inline _GLIBCXX14_CONSTEXPR void
    __advance(_InputIterator& __i, _Distance __n, input_iterator_tag)
    {
      // concept requirements
      __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>)
      __glibcxx_assert(__n >= 0);
      while (__n--)
    ++__i;
    }

bidirectional_iterator_tag 支持正向和反向移动。

  template<typename _BidirectionalIterator, typename _Distance>
    inline _GLIBCXX14_CONSTEXPR void
    __advance(_BidirectionalIterator& __i, _Distance __n,
          bidirectional_iterator_tag)
    {
      // concept requirements
      __glibcxx_function_requires(_BidirectionalIteratorConcept<
                  _BidirectionalIterator>)
      if (__n > 0)
        while (__n--)
      ++__i;
      else
        while (__n++)
      --__i;
    }

random_access_iterator_tag 直接通过 + 计算

  template<typename _RandomAccessIterator, typename _Distance>
    inline _GLIBCXX14_CONSTEXPR void
    __advance(_RandomAccessIterator& __i, _Distance __n,
              random_access_iterator_tag)
    {
      // concept requirements
      __glibcxx_function_requires(_RandomAccessIteratorConcept<
                  _RandomAccessIterator>)
      if (__builtin_constant_p(__n) && __n == 1)
    ++__i;
      else if (__builtin_constant_p(__n) && __n == -1)
    --__i;
      else
    __i += __n;
    }

5、insert_iterator

insert_iterator 构造于容器之上,将 iterator 的赋值操作,转换为容器的插入操作。

5.1、back_insert_iterator

back_insert_iterator 的赋值操作,转换为容器末尾的插入。

back_insert_iterator 属于 output_iterator_tag

  template<typename _Container>
    class back_insert_iterator
    : public iterator<output_iterator_tag, void, void, void, void>
    {
    protected:
      _Container* container;
      /* ... */
    };

operator=() 调用容器 push_back() 函数在末尾插入元素。

      _GLIBCXX20_CONSTEXPR
      back_insert_iterator&
      operator=(const typename _Container::value_type& __value)
      {
    container->push_back(__value);
    return *this;
      }

      _GLIBCXX20_CONSTEXPR
      back_insert_iterator&
      operator=(typename _Container::value_type&& __value)
      {
    container->push_back(std::move(__value));
    return *this;
      }

函数 back_inserter() 接受一个容器参数,构造一个 back_insert_iterator 对象。

  template<typename _Container>
    _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR
    inline back_insert_iterator<_Container>
    back_inserter(_Container& __x)
    { return back_insert_iterator<_Container>(__x); }

5.2、front_insert_iterator

front_insert_iterator 和 back_insert_iterator 类似,也是 output_iterator_tag 类型 iterator。

  template<typename _Container>
    class front_insert_iterator
    : public iterator<output_iterator_tag, void, void, void, void>
    {
    protected:
      _Container* container;
      /* ... */
    };

operator=() 调用容器 push_front() 函数在首部插入元素。

      _GLIBCXX20_CONSTEXPR
      front_insert_iterator&
      operator=(const typename _Container::value_type& __value)
      {
    container->push_front(__value);
    return *this;
      }

      _GLIBCXX20_CONSTEXPR
      front_insert_iterator&
      operator=(typename _Container::value_type&& __value)
      {
    container->push_front(std::move(__value));
    return *this;
      }

函数 front_inserter() 接受一个容器参数,构造一个 front_insert_iterator对象。

  template<typename _Container>
    _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR
    inline front_insert_iterator<_Container>
    front_inserter(_Container& __x)
    { return front_insert_iterator<_Container>(__x); }

5.3、insert_iterator

insert_iterator 也是 output_iterator_tag 类型迭代器。

  template<typename _Container>
    class insert_iterator
    : public iterator<output_iterator_tag, void, void, void, void>
    {
    protected:
      _Container* container;
      _Iter iter;
      /* ... */
    };

operator=() 调用容器 insert() 函数插入元素。

      _GLIBCXX20_CONSTEXPR
      insert_iterator&
      operator=(const typename _Container::value_type& __value)
      {
    iter = container->insert(iter, __value);
    ++iter;
    return *this;
      }

      _GLIBCXX20_CONSTEXPR
      insert_iterator&
      operator=(typename _Container::value_type&& __value)
      {
    iter = container->insert(iter, std::move(__value));
    ++iter;
    return *this;
      }

函数 inserter() 接受一个容器参数,构造一个 insert_iterator对象。

  template<typename _Container>
    _GLIBCXX_NODISCARD
    inline insert_iterator<_Container>
    inserter(_Container& __x, typename _Container::iterator __i)
    { return insert_iterator<_Container>(__x, __i); }

6、iterator adaptor

iterator 适配器将某个 iterator 封装成另一个 iterator,改变了原来 iterator 的行为。

6.1、reverse_iterator

bidirectional_iterator_tag 和 random_access_iterator_tag 都有相应的反向迭代器。

  template<typename _Iterator>
    class reverse_iterator
    : public iterator<typename iterator_traits<_Iterator>::iterator_category,
              typename iterator_traits<_Iterator>::value_type,
              typename iterator_traits<_Iterator>::difference_type,
              typename iterator_traits<_Iterator>::pointer,
                      typename iterator_traits<_Iterator>::reference>
    {

    protected:
      _Iterator current;
    /* ... */
    };

如果对 reverse_iterator 执行 ++,则原生 iterator 执行 --,反之亦然。+/- n 也是相同的逻辑。

      _GLIBCXX17_CONSTEXPR reverse_iterator&
      operator++()
      {
    --current;
    return *this;
      }

      _GLIBCXX17_CONSTEXPR reverse_iterator
      operator++(int)
      {
    reverse_iterator __tmp = *this;
    --current;
    return __tmp;
      }

      _GLIBCXX17_CONSTEXPR reverse_iterator&
      operator--()
      {
    ++current;
    return *this;
      }

      _GLIBCXX17_CONSTEXPR reverse_iterator
      operator--(int)
      {
    reverse_iterator __tmp = *this;
    ++current;
    return __tmp;
      }

比较反直觉的是 reverse_iterator::operator*()/operator->() 两个函数。返回的 --current 对应的值。因为容器 end() 返回的 iterator 并不是容器的最后一个元素,end() - 1 才是最后一个元素。

      _GLIBCXX_NODISCARD
      _GLIBCXX17_CONSTEXPR reference
      operator*() const
      {
    _Iterator __tmp = current;
    return *--__tmp;
      }

      _GLIBCXX_NODISCARD
      _GLIBCXX17_CONSTEXPR pointer
      operator->() const
      {
    // _GLIBCXX_RESOLVE_LIB_DEFECTS
    // 1052. operator-> should also support smart pointers
    _Iterator __tmp = current;
    --__tmp;
    return _S_to_pointer(__tmp);
      }

make_reverse_iterator() 函数返回 reverse_iterator 对象。

  template<typename _Iterator>
    [[__nodiscard__]]
    inline _GLIBCXX17_CONSTEXPR reverse_iterator<_Iterator>
    make_reverse_iterator(_Iterator __i)
    { return reverse_iterator<_Iterator>(__i); }

6.2、__gnu_cxx::__normal_iterator

__normal_iterator 适配器不会改变底层 iterator 的行为,其目的是将原始指针封装成一个普通的 iterator。

  template<typename _Iterator, typename _Container>
    class __normal_iterator
    {
    protected:
      _Iterator _M_current;
      /* ... */
    };

6.3、move_iterator

move_iterator 改变 iterator 解引用返回值类型:返回右值引用类型。

  template<typename _Iterator>
    class move_iterator
    {
      _Iterator _M_current;

      using __traits_type = iterator_traits<_Iterator>;
#if ! (__cplusplus > 201703L && __cpp_lib_concepts)
      using __base_ref = typename __traits_type::reference;
#endif

      using reference
    = __conditional_t<is_reference<__base_ref>::value,
              typename remove_reference<__base_ref>::type&&,
              __base_ref>;
        /* ... */
     };

make_move_iterator() 函数返回一个 move_iterator 对象。

  template<typename _Iterator>
    [[__nodiscard__]]
    inline _GLIBCXX17_CONSTEXPR move_iterator<_Iterator>
    make_move_iterator(_Iterator __i)
    { return move_iterator<_Iterator>(std::move(__i)); }

欢迎关注公众号“源知源为”,阅读更多技术干货
#STL##C++零基础学习#
C/C++基础 文章被收录于专栏

C/C++ 语言基础

全部评论

相关推荐

emmm别问我为啥上一条帖子隔了两个月我才开始投简历和拿offer,因为我懒😰简单流程如下:周一凌晨改好的简历,然后到处乱投简历;周二接到了三维家的一面通知,临时抱佛脚的背了一些八股;周三上午一面下午通知第二天hr面;周四上午hr面下午拿offer,遂收手支线:在BOSS上顺手投了几个大厂,投字节的时候不小心投城客户端了,结果过了一天HR突然把我简历要走了,还问我能不能整客户端,我直接一口答应(脏面评警告😢)结果在周三下午的时候给我打电话,说前端有空缺实习岗,问我有没有兴趣,然后就跟我约了周四下午一面😰我都没咋准备啊,咩都不会啊😭结果周四下午面完,晚上打电话通知过一面了,赶紧把二面约在下周一下午,留点缓冲时间。逆大天了,我一半的问题都不会,他居然给我过了?运气未免有点好了😥现在正在恶补计网、网安、性能优化的东西(这三大板块我是几乎一点不会,一面几乎一点答不出来,加上我又没怎么背八股,这块被干烂了😵)心得体会与经验:1.&nbsp;我giao怎么这么快就结束了,我还以为要找好久😨2.&nbsp;大厂的面试问题真的和中厂小厂很大不同,比如在三维家我能自己吹水到vue的数据劫持、Proxy代理响应式之类的他们就觉得很不错了,但是在字节你但凡敢提到一下就会追问你细节了,一追问马脚就全漏出来了3.&nbsp;有信心真的很重要,我感觉我能拿中厂offer最重要的就是吹水吹出自信来了,以至于三维家面试反问面试官有哪里还需要改进的时候,他就说很不错了解的很多😦4.&nbsp;理解很重要,我从头到尾真没背过很多八股,不过有一些知识确实是敲过代码验证过,所以面试的时候能吹水吹得出来😇想了解面经啥的可以直接评论区问我,但我可能也说不全,因为我没有记录,而且今天摆了一天感觉记忆快清空了😵下面是故事时间:我暑假刚开始的时候才开始准备八股,印象很深那个时候连什么原型、事件循环、闭包这些名词都没听过,资料也不知道怎么找,就一直零零散散的准备,感觉也只有js稍微背了一下八股,其他很多时候都是靠完全理解和手写熟悉一些机制的,但这样做效率很低,反正准备了一个多星期半个月就开摆了😭结果一摆就摆到了开学,笔记是乱七八糟的,八股是忘光光的,简历是一直没改的,实习也是一直没投过的。直到上周日晚上偶然和师兄聊天,他突然问我“你怎么还不找实习”,那天晚上才幡然醒悟,是时候做点事情了😡然后就按照上面描述的来走了。其实我感觉我从头到尾都没背特别多八股,也没怎么找刷题资料啥的,早期就是翻尚硅谷或者黑马的入门视频从头学起,中期用面试鸭看了一点点题,主要是在学js机制和敲js代码,后期才发现了w3c的面经网站,然后在那里看着学(那个时候已经懒得敲了,因为有些问题与代码感觉不像是给找实习的看的,忒细了点😂)接下来继续准备字节二面吧,虽然几乎没啥可能可以通过,但是万一有奇迹呢?😍😍😍也祝大家能够早日拿到心仪的offer
我的offer呢😡:我已经预见10天后你会发,节孝子启动了
投递三维家等公司10个岗位
点赞 评论 收藏
分享
Hyh_111:像这种hr就不用管了,基本没啥实力,换一个吧
点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务