stack_queue扩展学习 --- 反向迭代器
反向迭代器的实现思路
源码及框架分析
迭代器是用来遍历容器的,是一种封装,它不需要去关注容器的底层实现(底层是数组,链表,还是树等等这些结构),我们都是用统一的方式去对容器进行访问,访问行为是类似指针的。我们之前学习了普通迭代器和const迭代器:
- 普通迭代器:能读能写;
- const迭代器:只能读,只能遍历数据,得到数据,不能修改数据,是不能写的。
我们之前学的普通迭代器是正向迭代器,如果我想逆方向遍历呢?那么就需要反向迭代器。
SGI-STL30源代码,反向迭代器实现的核心源码在stl_iterator.h中,反向迭代器是一个适配器,各个容器中再适配出自己的反向迭代器,我们下面来看一看vector容器和list容器中的反向迭代器的核心部分:
在源码中,我们可以看到 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
内部可以通过迭代器萃取获取数据类型。迭代器萃取的本质是一种特化,我们主要使用通过模板参数传递数据类型的方式来实现。
反向迭代器本质上是一个适配器,使用模板实现。传递哪个容器的迭代器,就可以封装适配出对应的反向迭代器。因为反向迭代器的功能与正向迭代器的功能高度相似,只是遍历方向相反,例如 operator++
底层调用迭代器的 operator--
等,所以通过封装就可以实现。
比较奇怪的是 operator*
的实现。它内部访问的是迭代器当前位置的前一个位置。这需要结合容器中 rbegin
和 rend
的实现才能理解。rbegin
返回的是封装 end
位置的反向迭代器,rend
返回的是封装 begin
位置迭代器的反向迭代器。这里的设计是为了实现一种对称性,因此解引用访问的是当前位置的前一个位置。
反向迭代器的实现
反向迭代器通常是通过正向迭代器进行构造的。反向迭代器本质上是一个适配器,它对正向迭代器进行封装,从而实现反向遍历的功能。
反向迭代器的析构也不需要我们自己实现,因为迭代器不负责释放资源,释放资源是容器的事情!所以析构不需要写,就一般不需要写拷贝构造,因为不需要进行深拷贝!默认生成的浅拷贝就够用了!
重点实现的是:
operator*operator->operator++operator--
operator* 就是要返回当前迭代器指向的数据,当前指向的位置是一个正向迭代器,上面的对象是包装了一个反向迭代器的。operator* 解引用,不管是正向还是反向,都要返回数据的引用!
返回值类型设置
对于反向迭代器来说,operator*
的行为确实需要特别注意。反向迭代器的目的是让遍历方向与正向迭代器相反,因此它的 operator*
需要返回当前迭代器所指位置的前一个元素。这是因为反向迭代器的逻辑起点是容器的末尾(end()
),而不是开头(begin()
)。
-
正向迭代器:
begin()
指向第一个元素,end()
指向最后一个元素的下一个位置。 -
反向迭代器:
rbegin()
指向最后一个元素,rend()
指向第一个元素的前一个位置。
因此,反向迭代器的 operator*
实现为:
T& operator*() const { return *(current - 1); }
这里 current
是存储的正向迭代器,current - 1
表示前一个位置。
反向迭代器的模板参数
反向迭代器的模板参数设计取决于迭代器的类型和容器的特性。主要有以下两种情况:
a. 通用模板参数
对于通用的反向迭代器,模板参数通常包括:
-
Iterator
:正向迭代器类型。 -
T
:迭代器所指元素的类型。 -
Reference
:引用类型(T&
或const T&
)。 -
Distance
:迭代器距离类型(如std::ptrdiff_t
)。
template <class Iterator, class T, class Reference, class Distance>
class reverse_iterator {
public:Reference operator*() const { return *(current - 1); }// 其他成员函数...
private:Iterator current;
};
b. 偏特化和类型萃取
对于某些容器(如 std::vector
),其迭代器可能是原生指针,没有内嵌类型(如 reference
或 value_type
)。这种情况下,需要通过偏特化或类型萃取来获取正确的类型信息。
-
std::list
的迭代器:是一个自定义类型,可以通过typename Iterator::reference
获取引用类型。 -
std::vector
的迭代器:是一个原生指针,没有内嵌类型,需要通过偏特化或类型萃取来获取正确的类型。
template <class Iterator>
class reverse_iterator {
public:// 使用类型萃取获取引用类型using reference = typename std::iterator_traits<Iterator>::reference;reference operator*() const { return *(current - 1); }// 其他成员函数...
private:Iterator current;
};
为什么需要偏特化或类型萃取
-
std::list
的迭代器:是一个类模板实例,具有内嵌类型(如reference
和value_type
)。因此,可以直接通过typename Iterator::reference
获取引用类型。 -
std::vector
的迭代器:是一个原生指针(如T*
),没有内嵌类型。因此,需要通过偏特化或类型萃取来获取正确的类型。
template <class T>
class reverse_iterator<T*> {
public:using reference = T&;reference operator*() const { return *(current - 1); }// 其他成员函数...
private:T* current;
};
-
operator*
的行为:反向迭代器的operator*
返回当前迭代器所指位置的前一个元素。 -
模板参数设计:通用模板参数可以处理大多数情况,但对于原生指针类型的迭代器,需要通过偏特化或类型萃取来获取正确的类型信息。
-
类型萃取:通过
std::iterator_traits
可以统一处理不同类型迭代器的特性,包括原生指针和自定义迭代器。
其实就是总结为:
如果是普通迭代器,那就适配出普通反向迭代器:T& operator*,如果是const迭代器,就适配出const反向迭代器:const T& operator*,只是template<class Iterator>的话,是不能够的,Iterator内部有没有该数据类型?list是有的,以为list的iterator是一个自定义类型,直接使用typename Iterator::reference,也就是取他的内嵌类型(取内嵌类型需要加typename),但是vector就是一个原生指针,没有内嵌类型的概念,这时候就需要偏特化的类型萃取才可以搞定!
其实我们这里就不要那么复杂了,使用三个模板参数就可以了!
template<class Iterator, class Ref, class Ptr>
下面,为我们就可以实现一个:
Iterator.h
#pragma once// 反向迭代器模板
template<class Iterator, class Ref, class Ptr>
struct ReverseIterator
{typedef ReverseIterator<Iterator, Ref, Ptr> Self; // 自引用类型别名,方便后续使用// 构造函数:接受一个正向迭代器ReverseIterator(Iterator it): _it(it) // 初始化内部存储的正向迭代器{}// 解引用操作符:返回当前迭代器前一个位置的引用Ref operator*(){// 适配的不一定是随机迭代器,可能是双向迭代器或输入迭代器// 不是双向迭代器又不能减,只可以进行减减// 而且不能直接对_it"--"解引用,因为这会改变_it的值// 创建一个临时迭代器,向前移动一位Iterator tmp = _it;--tmp; // 确保迭代器支持--操作// 返回前一个位置的引用return *tmp;}// 成员访问操作符:返回解引用的地址Ptr operator->(){return &(operator*()); // 复用 operator* 的实现}// 前置递增操作符:递减内部迭代器Self& operator++(){--_it; // 内部迭代器向前移动return *this; // 返回当前反向迭代器}// 前置递减操作符:递增内部迭代器Self& operator--(){++_it; // 内部迭代器向后移动return *this; // 返回当前反向迭代器}// 不等于操作符:比较两个反向迭代器是否不相等bool operator!=(const Self& s){return _it != s._it; // 比较内部迭代器}// 等于操作符:比较两个反向迭代器是否相等bool operator==(const Self& s){return _it == s._it; // 比较内部迭代器}Iterator _it; // 内部存储的正向迭代器
};
我们就可以在List.h中进行反向迭代器的使用了:(结合上面图片进行代码的编写)
typedef list_iterator<T, T&, T*> iterator;typedef list_iterator<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(end());//}// 对称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());}
我们就可以在Vector.h中进行反向迭代器的使用了:
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;}
附录
迭代器类别 | 支持的操作 | 示例 |
---|---|---|
输入迭代器 (Input Iterator) | 单向遍历,支持 ++ 、* 、-> | std::istream_iterator |
输出迭代器 (Output Iterator) | 单向写入,支持 ++ 、* | std::ostream_iterator |
前向迭代器 (Forward Iterator) | 双向遍历,支持 ++ 、* 、-> | std::forward_list::iterator |
双向迭代器 (Bidirectional Iterator) | 双向遍历,支持 ++ 、-- 、* 、-> | std::list::iterator 、std::map::iterator |
随机访问迭代器 (Random Access Iterator) | 随机访问,支持 ++ 、-- 、+ 、- 、[] 、* 、-> | std::vector::iterator 、std::deque::iterator |
本片的全部正文:
反向迭代器https://gitee.com/small-entrepreneur/c-additional-meal