文章目录
- 1.迭代器的分类
- 2.反向迭代器的使用
- 3.反向迭代器的模拟实现
- 4.list类的反向迭代器实现
1.迭代器的分类
我们随便打开一个容器,看迭代器相关的接口,都可以发现,支持迭代器的容器,其迭代器有以下几类
- 正向迭代器
- const正向迭代器
- 反向迭代器
- const反向迭代器
2.反向迭代器的使用
对于正向迭代器,我么已经很熟悉了,在之前的STL容器的模拟实现中都已经实现过了。那么现在来看看反向迭代器
❗❗反向迭代器的特点
✅反向迭代器的迭代顺序与正向迭代器相反
✅rbegin()相当于end()
✅rend()相当于begin()
✅反向迭代器++相当于正向迭代器–
那么现在,让我们来看一看反向迭代器的使用与正向迭代器的区别
void Test1()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);
v.push_back(6);
auto rit = v.rbegin();
while (rit != v.rend())
{
cout << *rit << " ";
++rit;
}
cout << endl;
}
可以看到,反向迭代器的使用和正向迭代器没有任何区别,只是迭代的顺序不同。
3.反向迭代器的模拟实现
对于反向迭代器的实现,我们去参考一下库里面是怎么实现的
注:这里参照的库是SGI的3.0版本,与侯捷老师的STL源码剖析相对应
这里以list的反向迭代器实现为例,可以看到库里面对反向迭代器的实现是通过实例化reverse_iterator
类来实现的,通过用法可以推测出来reverse_iterator类模板的实现逻辑是通过传入的正向迭代器的类型来实例化出不同类的反向迭代器,这里反向迭代器就可以理解成一个容器适配器。
下面来看一下reverse_iterator类的实现,这个类在头文件stl_iterator中
通过观察库里面的代码,对模拟实现反向迭代器已经大概有了了解,但是其中出现了新语法:萃取,笔者正在学习的路上,目前的能力对萃取的理解有难度,所以本次模拟实现就不使用萃取的方式,而是使用和list迭代器同样的解决方案——传模板参数的方式解决【C++】list的模拟实现
所以,我们可以得到反向迭代器类的框架如下
template<class Iterator, class Ref, class Ptr>//这里对参数的设计参考之前list迭代器的这几
class reverse_iterator
{
typedef reserve_iterator<Iterator, Ref, Ptr> Self;//这里类型实例化出来太长了,做一个重命名
public:
//......
private:
Iterator _it;
};
成员函数的实现
参照list迭代器类的成员函数,我们需要设计的成员函数有:
- 解引用
- 前置后置的++–
- ->运算符
- != 和==
按照我们的理解,很轻松能够写出来以下的成员函数。
reverse_iterator(Iterator it)//构造函数
:_it(it)
{}
Self& operator++()//前置++
{
--_it;
return *this;
}
Self operator++(int)//后置++
{
Self tmp = _it;
--_it;
return tmp;
}
Self& operator--()//前置--
{
++_it;
return *this;
}
Self operator--(int)//后置--
{
Self tmp = _it;
++_it;
return tmp;
}
Ref operator*()
{
return *this;
}
Ptr operator->()
{
return &(operator*());
}
bool operator!=(const Self& s) const
{
return _it != s._it;
}
bool operator==(const Self& s) const
{
return _it == s._it;
}
接下来和库里面的对比以下吧
诶?这和我们实现的不一样啊,为啥嘞?“源码之下了无秘密”,我们去看一下list中对迭代器接口的实现
哦哦懂了,原来是这样,在list中对rbegin的实现是使用end()构造的,end返回的是最后一个元素的下一个位置
如果我们要拿到最后一个元素,会调用rbegin()接口,此时如果要拿到最后一个元素,当然要让rbegin先–,指向最后一个元素之后再解引用。
所以最终对于*得到了以下实现,其余不用改变
当然,如果你愿意更改所有容器对反向迭代器的传参,也可以按照上文中的实现方式实现。
Ref operator*()
{
Iterator tmp = _it;
return *(--tmp);
}
最后,我们对返现迭代器类的实现完整代码如下
namespace zht
{
template<class Iterator, class Ref, class Ptr>//这里对参数的设计参考之前list迭代器的这几
class reverse_iterator
{
typedef reserve_iterator<Iterator, Ref, Ptr> Self;//这里类型实例化出来太长了,做一个重命名
public:
reverse_iterator(Iterator it)//构造函数
:_it(it)
{}
Self& operator++()//前置++
{
--_it;
return *this;
}
Self operator++(int)//后置++
{
Self tmp = _it;
--_it;
return tmp;
}
Self& operator--()//前置--
{
++_it;
return *this;
}
Self operator--(int)//后置--
{
Self tmp = _it;
++_it;
return tmp;
}
Ref operator*()
{
Iterator tmp = _it;
return *(--tmp);
}
Ptr operator->()
{
return &(operator*());
}
bool operator!=(const Self& s) const
{
return _it != s._it;
}
bool operator==(const Self& s) const
{
return _it == s._it;
}
private:
Iterator _it;
};
}
4.list类的反向迭代器实现
有了上述迭代器类的实现,我们现在可以顺便把之前模拟实现的list类中的反向迭代器加上了
typedef zht::reverse_iterator<iterator, T&, T*> reverse_iterator;//反向迭代器
typedef zht::reverse_iterator<const_iterator, const T&, const T*> const_reverse_iterator;//const反向迭代器
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());
}
至此,就把STL的迭代器完整实现了。