目录
前言
前面我们已经实现了很多的容器,但是我们都没有来实现反向迭代器,下面我们来模拟实现一个简单的反向迭代器
一、反向迭代器介绍
C++一共有4种迭代器,我们只剩下了反向迭代器,反向迭代器的使用与其它迭代器的使用并没有什么不同,与正向迭代器进行对比,正向迭代器++是向容器的下一个元素移动,而反向迭代器的++是向前一个元素移动,反向迭代器的很多行为与正向迭代器是相反的,由此我们也就清楚了,反向迭代器的思路。
二、实现反向迭代器
我们知道对于不同的容器他们的迭代器的功能是类似的,以list举例,我们要实现它的反向迭代器只要修改正向迭代器,实现出一份反向迭代器就好了,而对于vector同理。
但是这种做法具有很多重复代码,并且十分的占用内存,我们前面实现了容器适配器,所以我们可以仿照容器适配器,来实现一个反向迭代器。
我们可以使用正向迭代器来构造,反向迭代器的++就是正向迭代器的--,然后其它成员函数类似
我们可以看一下库中是如何实现的,从而验证一下我们的思路
reverse_bidirectional_iterator() {}
explicit reverse_bidirectional_iterator(BidirectionalIterator x)
: current(x) {}
BidirectionalIterator base() const { return current; }
Reference operator*() const {
BidirectionalIterator tmp = current;
return *--tmp;
}
#ifndef __SGI_STL_NO_ARROW_OPERATOR
pointer operator->() const { return &(operator*()); }
#endif /* __SGI_STL_NO_ARROW_OPERATOR */
self& operator++() {
--current;
return *this;
}
self operator++(int) {
self tmp = *this;
--current;
return tmp;
}
self& operator--() {
++current;
return *this;
}
self operator--(int) {
self tmp = *this;
++current;
return tmp;
}
};
我们看库中的*操作符重载,发现它构造了一个临时对象,然后返回的是临时对象减减之后的位置
这到底是为什么呢?
这里有两个问题
1、为什么要返回临时对象
2、为什么要先减减,再返回
这里是有原因的,我们只要想明白一点,这两个问题就都会被解决
以上的两个问题一定跟传入的迭代器有关,因为要使用已经实现的正向迭代器去实现一个反向迭代器。
同时我们要知道,正向迭代器的begin指向第一个有效元素,end指向最后一个元素的下一个位置
我们再看看list中反向迭代器的声明和定义
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());
}
我们发现库中的反向迭代器与正向迭代器形成对称,也就是那正向迭代器的begin构造反向迭代器的end,正向迭代器的end构造反向迭代器的begin。
正是这种构造方法所以才会导致反向迭代器的*是这个样子,所以--的原因弄清楚了,接下来是为什么要返回临时对象的原因,这个原因也比较简单,我们平时在使用迭代器的时候,我们都会手动的++或者--迭代器,来完成遍历,如果我们在底层让this自身++或者--,就会导致迭代器指向的位置发生变化,然后我们在外面手动++ --一下,我们就会跳两步,导致有些元素没有被遍历。
反向迭代器也需要考虑const反向迭代器,处理方法与const的正向迭代器的处理方法一样,在模板上传3个参数,根据实例化的不同来选择调用的是普通反向迭代器还是const迭代器
剩下的部分与list实现迭代器的思路大体相同,不过要想清楚++和--以及解引用的实现细节
//reverse_iterator.hpp
#pragma once
#include<iostream>
#include<string>
using namespace std;
namespace ww
{
template<class Iterator, class Ref, class Ptr>
struct __reserve_iterator
{
typedef __reserve_iterator<Iterator, Ref, Ptr> Riterator;
__reserve_iterator(Iterator it)
:_cur(it)
{}
Riterator operator++()
{
--_cur;
return *this;
}
Riterator operator++(int)
{
Iterator tmp(*this);
--_cur;
return tmp;
}
Ref operator*()
{
Iterator tmp = _cur;
return *--tmp;
}
Riterator operator--()
{
++_cur;
return *this;
}
Riterator operator--(int)
{
Iterator tmp(*this);
++_cur;
return tmp;
}
Ptr operator->()
{
return &(operator*());
}
bool operator!=(const Riterator it)const
{
return _cur != it._cur;
}
bool operator==(const Riterator it)const
{
return _cur == it._cur;
}
Iterator _cur;
};
}
总结
以上就是今天要讲的内容,反向迭代器的模拟实现除了显式的传3个模板参数外,还可以使用迭代器萃取,来解决const迭代器的问题