反向迭代器(reverse_iterator)的模拟实现
在C++中,每一种容器的反向迭代器(如果有迭代器的话)并不是都单独去写了一种放在了那个容器中,而是统一的做了一个反向迭代器的模板。
也就是迭代器适配器。
它会根据被传过来的容器的迭代器来相应的去生成对应的反向迭代器。
这里模拟一下大致的底层原理
// 注意:这个只是模拟,跟库里的不太一样
template <class Iterator, class Ref, class Ptr>
struct ReverseIterator
{
typedef ReverseIterator<Iterator, Ref, Ptr> Self;
Iterator _it;
ReverseIterator(Iterator it) // 根据传过来的迭代器来进行构造
: _it(it)
{
}
Ref operator*()
{
// return *_it; // 库里的*并不是这样做的
// 而是这样
Iterator tmp = _it;
return *(--tmp);
// 原因是:库里的rbegin,用的是原本迭代器的end(也就是哨兵位)去构造的,直接 *_it 得到的是哨兵位里存的数据,这不就跟我们想要的不一致了
// 库里的rend,用的是原本迭代器的begin(也就是哨兵位的后一个结点,第一个有效结点)去构造的
// 那为什么库里不选择:用原本迭代器的--end(也就是哨兵位的前一个结点,最后一个有效结点)去构造rbegin
// 用原本迭代器的end(也就是哨兵位)去构造rend
// 库里这样做的原因是:为了能够跟原本迭代器的 begin 和 end 形成对称
// 那为什么不这样写呢?
// return *(--_it);
// 答:*(解引用)的目的只是要访问数据,怎么能把迭代器都修改了呢?如果这样写,你连续多用几次*,都不需要循环就已经把迭代器走完了
}
Ptr operator->()
{
// return _it->; // 这里这样写的话编译不会报错,但实际上用的时候还是可能会出现问题的,因为这个表达式并不完整
// return _it.operator->();
// 为了保证反向迭代器的正确性(就是要能达到我们想要的效果)
return &(operator*()); // 直接就这样写了
}
Self &operator++() // 这里就写一下前置的++
{
--_it;
return *this
}
Self &operator--()
{
++_it;
return *this;
}
bool operator!=(const Self &s)
{
return _it != s._it;
}
};
补充:迭代器从性质方面的分类
1、单向
ex:forward_list(单向链表的迭代器) // 只支持++ // 单向迭代器没有对应的反向迭代器(因为它不支持--)
2、双向
ex:list(双向链表的迭代器) // 支持++、--
3、随机
ex:vector/deque // 支持++、--、+、-
补充:迭代器从功能方面的分类
1、正向
2、反向
3、const