一、前言
在 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*需要访问当前位置的前一个位置,才能保证解引用结果正确。- 适配器模式让容器只需提供正向迭代器,就能低成本地获得完整的反向遍历能力。