迭代器是用来遍历容器的,是一种封装,它不需要去关注容器的底层实现(底层是数组,链表,还是树等等这些结构),我们都是用统一的方式去对容器进行访问,访问行为是类似指针的。我们之前学习了普通迭代器和const迭代器:
我们之前学的普通迭代器是正向迭代器,如果我想逆方向遍历呢?那么就需要反向迭代器。
SGI-STL30源代码,反向迭代器实现的核心源码在stl_iterator.h中,反向迭代器是一个适配器,各个容器中再适配出自己的反向迭代器,我们下面来看一看vector容器和list容器中的反向迭代器的核心部分:
在源码中,我们可以看到 reverse_iterator
实现了两个版本。通过 __STL_CLASS_PARTIAL_SPECIALIZATION
条件编译来控制使用哪个版本。简单来说,支持偏特化的迭代器萃取以后,反向迭代器使用的是以下版本:
template
class reverse_iterator;
而之前使用的是以下版本:
template
class reverse_bidirectional_iterator;
template
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
表示前一个位置。
反向迭代器的模板参数设计取决于迭代器的类型和容器的特性。主要有以下两种情况:
对于通用的反向迭代器,模板参数通常包括:
Iterator
:正向迭代器类型。
T
:迭代器所指元素的类型。
Reference
:引用类型(T&
或 const T&
)。
Distance
:迭代器距离类型(如 std::ptrdiff_t
)。
template
class reverse_iterator {
public:
Reference operator*() const { return *(current - 1); }
// 其他成员函数...
private:
Iterator current;
};
对于某些容器(如 std::vector
),其迭代器可能是原生指针,没有内嵌类型(如 reference
或 value_type
)。这种情况下,需要通过偏特化或类型萃取来获取正确的类型信息。
std::list
的迭代器:是一个自定义类型,可以通过 typename Iterator::reference
获取引用类型。
std::vector
的迭代器:是一个原生指针,没有内嵌类型,需要通过偏特化或类型萃取来获取正确的类型。
template
class reverse_iterator {
public:
// 使用类型萃取获取引用类型
using reference = typename std::iterator_traits::reference;
reference operator*() const { return *(current - 1); }
// 其他成员函数...
private:
Iterator current;
};
std::list
的迭代器:是一个类模板实例,具有内嵌类型(如 reference
和 value_type
)。因此,可以直接通过 typename Iterator::reference
获取引用类型。
std::vector
的迭代器:是一个原生指针(如 T*
),没有内嵌类型。因此,需要通过偏特化或类型萃取来获取正确的类型。
template
class reverse_iterator {
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
其实我们这里就不要那么复杂了,使用三个模板参数就可以了!
template
下面,为我们就可以实现一个:
#pragma once
// 反向迭代器模板
template
struct ReverseIterator
{
typedef ReverseIterator 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 iterator;
typedef list_iterator const_iterator;
typedef ReverseIterator reverse_iterator;
typedef ReverseIterator 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 reverse_iterator;
typedef ReverseIterator 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