C++ STL 反向迭代器:从源码框架到适配器实现

一、前言

在 C++ STL 中,反向迭代器(reverse_iterator)是一个很典型的设计案例:它本身并不直接持有容器数据,而是通过封装一个正向迭代器,把「前进」变成「后退」,从而让同一个容器既能正序遍历,也能逆序遍历。

本文从 SGI-STL 3.0 的源码框架出发,梳理反向迭代器的设计思路,再手写一个通用的迭代器适配器,并在 vector 和 list 中完成适配与测试。

二、源码及框架分析

2.1 容器中的反向迭代器定义

在 SGI-STL 3.0 中,反向迭代器的核心源码位于 stl_iterator.h。反向迭代器是一个适配器 ,各个容器再基于它适配出自己的反向迭代器类型。下面截取 list 与 vector 的关键部分。

cpp 复制代码
// stl_list.h
template <class T, class Alloc = alloc>
class list {
public:
  typedef __list_iterator<T, T&, T*>             iterator;
  typedef __list_iterator<T, const T&, const T*> const_iterator;
#ifdef __STL_CLASS_PARTIAL_SPECIALIZATION
  typedef reverse_iterator<const_iterator> const_reverse_iterator;
  typedef reverse_iterator<iterator> reverse_iterator;
#else /* __STL_CLASS_PARTIAL_SPECIALIZATION */
  typedef reverse_bidirectional_iterator<const_iterator, value_type,
  const_reference, difference_type> const_reverse_iterator;
  typedef reverse_bidirectional_iterator<iterator, value_type, reference,
  difference_type> reverse_iterator;
#endif /* __STL_CLASS_PARTIAL_SPECIALIZATION */

  iterator begin() { return (link_type)((*node).next); }
  const_iterator begin() const { return (link_type)((*node).next); }
  iterator end() { return node; }
  const_iterator end() const { return node; }

  reverse_iterator rbegin() { return reverse_iterator(end()); }
  const_reverse_iterator rbegin() const {
    return const_reverse_iterator(end());
  }
  reverse_iterator rend() { return reverse_iterator(begin()); }
  const_reverse_iterator rend() const {
    return const_reverse_iterator(begin());
  }
};
cpp 复制代码
// stl_vector.h
template <class T, class Alloc = alloc>
class vector {
public:
  typedef T value_type;
  typedef value_type* iterator;
#ifdef __STL_CLASS_PARTIAL_SPECIALIZATION
  typedef reverse_iterator<const_iterator> const_reverse_iterator;
  typedef reverse_iterator<iterator> reverse_iterator;
#else /* __STL_CLASS_PARTIAL_SPECIALIZATION */
  typedef reverse_iterator<const_iterator, value_type, const_reference,
                           difference_type>  const_reverse_iterator;
  typedef reverse_iterator<iterator, value_type, reference, difference_type>
          reverse_iterator;
#endif /* __STL_CLASS_PARTIAL_SPECIALIZATION */

  iterator begin() { return start; }
  const_iterator begin() const { return start; }
  iterator end() { return finish; }
  const_iterator end() const { return finish; }

  reverse_iterator rbegin() { return reverse_iterator(end()); }
  const_reverse_iterator rbegin() const {
    return const_reverse_iterator(end());
  }
  reverse_iterator rend() { return reverse_iterator(begin()); }
  const_reverse_iterator rend() const {
    return const_reverse_iterator(begin());
  }
};

2.2 两个版本的 reverse_iterator

源码中可以看到 reverse_iterator 实现了两个版本,通过 __STL_CLASS_PARTIAL_SPECIALIZATION 条件编译控制使用哪一个:

  • 支持偏特化的迭代器萃取之后,使用 template <class Iterator> class reverse_iterator; 版本;
  • 在此之前,使用 template <class BidirectionalIterator, class T, class Reference, class Distance> class reverse_bidirectional_iterator; 以及 template <class RandomAccessIterator, class T, class Reference, class Distance> class reverse_iterator; 版本。

两者的差别主要在于模板参数是否需要显式传递迭代器指向的数据类型。支持偏特化的迭代器萃取之后就不需要再传了,因为 reverse_iterator 内部可以通过迭代器萃取获取数据类型。迭代器萃取的本质是一种特化,细节相对复杂且不影响学习主线,这里不展开讲解,有兴趣的同学可以自行阅读源码。

本文主要采用模板参数传递数据类型的方式来实现。

2.3 适配器思路

反向迭代器本质上是一个适配器,使用模板实现:传递哪个容器的迭代器,就可以封装适配出对应的反向迭代器。因为反向迭代器的功能与正向迭代器高度相似,只是遍历方向相反,例如 operator++ 底层调用迭代器的 operator--,所以封装一层就可以实现。

比较奇怪的是 operator* 的实现,内部访问的是迭代器当前位置的前一个位置 。这一点要结合容器中 rbegin 和 rend 的实现才能看懂:rbegin 返回的是封装 end 位置的反向迭代器,rend 返回的是封装 begin 位置的反向迭代器。这里是为了实现出一个对称,所以解引用访问的是当前位置的前一个位置。

三、实现反向迭代器

3.1 通用迭代器适配器

cpp 复制代码
// ReverseIterator.h
// 所有容器的反向迭代器
// 迭代器适配器
namespace bit
{
    template<class Iterator, class Ref, class Ptr>
    struct ReverseIterator
    {
        typedef ReverseIterator<Iterator, Ref, Ptr> Self;

        // 正向迭代器
        Iterator _it;

        ReverseIterator(Iterator it)
            :_it(it)
        {}

        Ref operator*()
        {
            Iterator tmp = _it;
            return *(--tmp);
        }

        Ptr operator->()
        {
            return &(operator*());
        }

        Self& operator++()
        {
            --_it;
            return *this;
        }

        Self& operator--()
        {
            ++_it;
            return *this;
        }

        Self operator++(int)
        {
            Self tmp(*this);
            --_it;
            return tmp;
        }

        Self operator--(int)
        {
            Self tmp(*this);
            ++_it;
            return tmp;
        }

        bool operator!=(const Self& s) const
        {
            return _it != s._it;
        }

        bool operator==(const Self& s) const
        {
            return _it == s._it;
        }
    };
}

3.2 在 vector 中适配

cpp 复制代码
// vector.h
#include "ReverseIterator.h"

namespace bit
{
    template<class T>
    class vector
    {
    public:
        typedef T* iterator;
        typedef const T* const_iterator;
        typedef ReverseIterator<iterator, T&, T*> reverse_iterator;
        typedef ReverseIterator<const_iterator, const T&, const T*>
                const_reverse_iterator;

        reverse_iterator rbegin()
        {
            return reverse_iterator(end());
        }

        reverse_iterator rend()
        {
            return reverse_iterator(begin());
        }

        const_reverse_iterator rbegin() const
        {
            return const_reverse_iterator(end());
        }

        const_reverse_iterator rend() const
        {
            return const_reverse_iterator(begin());
        }

        iterator begin()
        {
            return _start;
        }

        iterator end()
        {
            return _finish;
        }

        const_iterator begin() const
        {
            return _start;
        }

        const_iterator end() const
        {
            return _finish;
        }

        // ....
    private:
        iterator _start = nullptr;
        iterator _finish = nullptr;
        iterator _endofstorage = nullptr;
    };
}

3.3 在 list 中适配

cpp 复制代码
// list.h
#include "ReverseIterator.h"

namespace bit
{
    template<class T>
    class list
    {
        typedef ListNode<T> Node;
    public:
        typedef ListIterator<T, T&, T*> iterator;
        typedef ListIterator<T, const T&, const T*> const_iterator;
        typedef ReverseIterator<iterator, T&, T*> reverse_iterator;
        typedef ReverseIterator<const_iterator, const T&, const T*>
                const_reverse_iterator;

        reverse_iterator rbegin()
        {
            return reverse_iterator(end());
        }

        reverse_iterator rend()
        {
            return reverse_iterator(begin());
        }

        const_reverse_iterator rbegin() const
        {
            return const_reverse_iterator(end());
        }

        const_reverse_iterator rend() const
        {
            return const_reverse_iterator(begin());
        }

        iterator begin()
        {
            return _head->_next;
        }

        iterator end()
        {
            return _head;
        }

        const_iterator begin() const
        {
            return _head->_next;
        }

        const_iterator end() const
        {
            return _head;
        }

        // ...
    private:
        Node* _head;
        size_t _size;
    };
}

3.4 测试代码

cpp 复制代码
// test.cpp
#include "list.h"
#include "vector.h"

int main()
{
    bit::list<int> lt = { 1,2,3,4 };
    bit::list<int>::reverse_iterator rit = lt.rbegin();
    while (rit != lt.rend())
    {
        //*rit = 1;
        cout << *rit << " ";
        ++rit;
    }
    cout << endl;
    return 0;
}

//int main()
//{
//    bit::vector<int> v = { 1,2,3,4 };
//    bit::vector<int>::reverse_iterator rit = v.rbegin();
//    while (rit != v.rend())
//    {
//        //*rit = 1;
//        cout << *rit << " ";
//        ++rit;
//    }
//    cout << endl;
//
//    return 0;
//}

四、小结

  • 反向迭代器是一个迭代器适配器 ,通过封装正向迭代器实现方向反转,一套模板即可复用于 vector、list 等容器。
  • rbegin() 封装 end(),rend() 封装 begin(),因此 operator* 需要访问当前位置的前一个位置,才能保证解引用结果正确。
  • 适配器模式让容器只需提供正向迭代器,就能低成本地获得完整的反向遍历能力。
相关推荐
青少儿编程课堂44 分钟前
蓝桥杯青少组图形化 + 全国青少年信息素养大赛 + 电子学会Scratch考级:校园成语接龙大挑战解析
c++·python·算法·bfs·信息学竞赛
小贾要学习1 小时前
【C++后端开发项目】Reactor 模型 / C++ 仿写 muduo HTTP 服务器:让底层网络库真正跑起网页
linux·服务器·c++·http·网络编程·muduo·reactor模型
老师我太想进步了20261 小时前
【数据结构-1】例解算法复杂度
数据结构·算法
tyler_download2 小时前
deepseek后训练算法:位置编码算法RoPE详解1
算法
A7bert7772 小时前
【MobileSAM部署至RK3588】环境适配→转换RKNN→开发板部署
c++·人工智能·深度学习·目标检测·ubuntu
青少儿编程课堂2 小时前
蓝桥杯·全国青少年信息素养大赛·电子学会C/C++考级:分层图最短路解析
c++·python·算法·bfs·信息学竞赛
YSL0701243 小时前
一文通关-----排序
数据结构·算法
FlightYe12 小时前
视界原理之3D视频(四):裸眼、眼镜和头显
android·linux·c++·3d·ffmpeg·音视频
ZhengEnCi13 小时前
GPT-6 Astra 爆改 Qwen 权重真有那么神吗:权重空间编程 0.016% 参数的真相
算法·架构