c++
标准库标准库实现了很多容器,容器的使用过程中我们有基于容器位置获取或设置位置元素,位置前进或后退,位置比较的需求。将这类容器位置相关的需求封装起来就是迭代器。
c++
标准库容器有很多,不同的容器对位置的管理有不同的要求,如数组可以直接依据索引到达目标位置,而链表只能逐个前进到达目标位置。为了对这些不同的位置管理进行抽象分类。标准库最终定义了五类迭代器。
这五类迭代器分别用以下类别来表示
struct input_iterator_tag {};
struct output_iterator_tag {};
struct forward_iterator_tag : public input_iterator_tag {};
struct bidirectional_iterator_tag : public forward_iterator_tag {};
struct random_access_iterator_tag : public bidirectional_iterator_tag {};
c++
基于模板实现泛型编程,不像java
基于接口实现。模板中对模板类型参数的要求没办法通过明确的类型定义给出来,只能通过约定熟成的方式希望类的使用者,实现者都明白来保证正确性。
泛型的好处是,对于类型定义,一个定义实现可以适用于多种模板参数类型,比如char
,int
可以共用一份vector
模板实现。对于模板函数也是如此。但其中隐藏的陷进是类的实现者,类的使用者必须就模板实现中对模板类型的要求达成约定熟成的一致观点。
当我们要使用或实现对应类别的迭代器时,我们必须要清楚每种类别的迭代器实现上的要求。
2.1.迭代器的规范
input_iterator_tag 迭代器是一种单向迭代器,只能向前遍历序列,且不能后退。
input_iterator_tag 迭代器的规范:
class InputIterator {
public:
using value_type = ...; // 假设我们正在迭代整数
using reference = ...;
using pointer = ...;
using difference_type = ...;
using iterator_category = std::input_iterator_tag; // 这是输入迭代器的类别标签
InputIterator(...) : ... {}
InputIterator& operator++() { // 前置 ++
...
}
bool operator==(const InputIterator& other) const { // 相等运算符
...
}
bool operator!=(const InputIterator& other) const { // 不等运算符
...
}
const reference operator*() const { // 解引用运算符
...
}
};
如上所示,对input_iterator_tag
类别的迭代器的实现要求是:
(1). 迭代器类型内部需定义value_type
,reference
,pointer
,difference_type
,iterator_category
内部类型。
a. value_type
一般表示迭代位置的元素的值类型。
b. reference
一般表示值类型的引用。
c. pointer
一般表示值的指针。
d. difference_type
,一般表示两个位置间差值。
e. iterator_category
,迭代器类别。这里应该固定为input_iterator_tag
。
(2). 迭代器类型应该提供前置++
。
(3). 允许对迭代器iter
实例执行*iter
来访问所在位置的元素。上述实例中operator*()
返回const reference
使得其恰好满足input_iterator_tag
迭代器的要求,但若某个input_iterator_tag
实现返回reference
也是可以的。这时,这个实现既满足input_iterator_tag
要求,又在要求的基础上提供了进一步的功能扩展。但以input_iterator_tag
类别参与泛型编程时, 使用者对input_iterator_tag
实例的预期应该是可执行*iter
获得迭代器位置下的值,不应持有*iter=value;
的预期。
(4). 迭代器类型应该提供==
,!=
运算符。
2.2.标准库中的实例
template<typename _Category, typename _Tp, typename _Distance = ptrdiff_t, typename _Pointer = _Tp*, typename _Reference = _Tp&>
struct iterator
{
typedef _Category iterator_category;
typedef _Tp value_type;
typedef _Distance difference_type;
typedef _Pointer pointer;
typedef _Reference reference;
};
template<typename _Tp, typename _CharT = char, typename _Traits = char_traits<_CharT>, typename _Dist = ptrdiff_t>
class istream_iterator : public iterator<input_iterator_tag, _Tp, _Dist, const _Tp*, const _Tp&>
{
public:
typedef _CharT char_type;
typedef _Traits traits_type;
typedef basic_istream<_CharT, _Traits> istream_type;
private:
istream_type* _M_stream;
_Tp _M_value;
bool _M_ok;
public:
istream_iterator(istream_type& __s) : _M_stream(&__s) { _M_read(); }
const _Tp& operator*() const {
return _M_value;
}
istream_iterator& operator++() {
_M_read();
return *this;
}
istream_iterator operator++(int) {
istream_iterator __tmp = *this;
_M_read();
return __tmp;
}
const _Tp* operator->() const { return &(operator*()); }
bool _M_equal(const istream_iterator& __x) const {
return (_M_ok == __x._M_ok) && (!_M_ok || _M_stream == __x._M_stream);
}
private:
void _M_read() {
_M_ok = (_M_stream && *_M_stream) ? true : false;
if (_M_ok) {
*_M_stream >> _M_value;
_M_ok = *_M_stream ? true : false;
}
}
};
template<typename _Tp, typename _CharT, typename _Traits, typename _Dist>
inline bool operator==(const istream_iterator<_Tp, _CharT,
_Traits, _Dist>& __x, const istream_iterator<_Tp, _CharT, _Traits, _Dist>& __y)
{ return __x._M_equal(__y); }
template <class _Tp, class _CharT, class _Traits, class _Dist>
inline bool operator!=(const istream_iterator<_Tp, _CharT,
_Traits, _Dist>& __x, const istream_iterator<_Tp, _CharT, _Traits, _Dist>& __y)
{ return !__x._M_equal(__y); }
忽略无关部分,我们来检查该实现对规范的遵循情况:
(1). 迭代器类型内部需定义value_type
,reference
,pointer
,difference_type
,iterator_category
内部类型。
上述实现通过公共继承iterator
来完成此项工作。
(2). 迭代器类型应该提供前置++
运算符。
(3). 允许对迭代器iter
实例执行*iter
来访问所在位置的元素。
因为是输入迭代器,这里返回的const _Tp&
类型使得使用者针对该迭代器只能执行xxx = *iter
,无法执行*iter = xxx;
(4). 迭代器类型应该提供==
,!=
运算符
3.1.迭代器规范
output_iterator_tag
迭代器的规范:
#include
#include
class MyOutputIterator {
public:
using iterator_category = std::output_iterator_tag;
using value_type = xxx;
using difference_type = xxx;
using pointer = xxx;
using reference = xxx;
MyOutputIterator(xxx) : ... {}
MyOutputIterator& operator=(const value_type & value) {
...
}
MyOutputIterator& operator*() {
...
}
MyOutputIterator& operator++() {
...
}
MyOutputIterator operator++(int) {
...
}
...
};
(1). 需要定义以下内部类别
iterator_category
,必须固定为std::output_iterator_tag
。
value_type
,一般为迭代器位置下的值类型。
difference_type
,用于表示两个迭代器位置的差值。
pointer
,一般为迭代器位置。
reference
,一般为值的引用。
(2). 运算符重载,需要重载前置++
(3). 对迭代器实例iter
,支持*iter=value;
来设置位置下的值。
和input_iterator_tag
类别迭代器区别:
(1). input_iterator_tag
迭代器类别强调的是通过*iter
来访问位置下的值,output_iterator_tag
强调的是通过*iter=value;
来设置位置下的值。
(2). input_iterator_tag
额外强调了==
,!=
。output_iterator_tag
额外强调了后置++
。
3.2.标准库中实例
#define __PTRDIFF_TYPE__ long int
typedef __SIZE_TYPE__ size_t;
typedef __PTRDIFF_TYPE__ ptrdiff_t;
template<typename _Category, typename _Tp, typename _Distance = ptrdiff_t, typename _Pointer = _Tp*, typename _Reference = _Tp&>
struct iterator
{
typedef _Category iterator_category;
typedef _Tp value_type;
typedef _Distance difference_type;
typedef _Pointer pointer;
typedef _Reference reference;
};
template<typename _Container>
class back_insert_iterator : public iterator<output_iterator_tag, void, void, void, void>
{
protected:
_Container* container;
public:
typedef _Container container_type;
explicit back_insert_iterator(_Container& __x) : container(&__x) { }
#if __cplusplus < 201103L
back_insert_iterator& operator=(typename _Container::const_reference __value)
{
container->push_back(__value);
return *this;
}
#else
back_insert_iterator& operator=(const typename _Container::value_type& __value)
{
container->push_back(__value);
return *this;
}
back_insert_iterator& operator=(typename _Container::value_type&& __value)
{
container->push_back(std::move(__value));
return *this;
}
#endif
back_insert_iterator& operator*()
{ return *this; }
back_insert_iterator& operator++()
{ return *this; }
back_insert_iterator operator++(int)
{ return *this; }
};
忽略无关部分,我们来检查该实现对规范的遵循情况:
(1). 迭代器类型内部需定义value_type
,reference
,pointer
,difference_type
,iterator_category
内部类型。
上述实现通过公共继承iterator
来完成此项工作。
(2). 迭代器类型应该提供前置++
。
(3). 允许对迭代器iter
实例执行*iter=value
来设置所在位置的元素。
(4). 迭代器类型应该提供后置++
。
4.1. 迭代器规范
forward_iterator_tag
迭代器规范:
class MyForwardIterator {
public:
using iterator_category = std::forward_iterator_tag;
using value_type = xxx;
using difference_type = xxx;
using pointer = xxx;
using reference = xxx;
MyForwardIterator(xxx) : ... {}
MyForwardIterator& operator++() {
...
}
bool operator==(const MyForwardIterator& other) const {
...
}
bool operator!=(const MyForwardIterator& other) const {
...
}
reference operator*() const {
...
}
...
};
如上所示,对forward_iterator_tag
类别的迭代器的实现要求是:
(1). 迭代器类型内部需定义value_type
,reference
,pointer
,difference_type
,iterator_category
内部类型。
a. value_type
一般表示迭代位置的元素的值类型。
b. reference
一般表示值类型的引用。
c. pointer
一般表示值的指针。
d. difference_type
,一般表示两个位置间差值。
e. iterator_category
,迭代器类别。这里应该固定为forward_iterator_tag
。
(2). 迭代器类型应该提供前置++
,==
,!=
运算符。
(3). 允许对迭代器iter
实例执行*iter
来访问所在位置的元素。
(4). 允许对迭代器iter
实例执行*iter = value
来设置所在位置的元素。
和input_iterator_tag
类别迭代器区别:
a. forward_iterator_tag
其实就是input_iterator_tag+(4)
。
4.2.标准库中的实例
template<typename _Tp>
struct _Fwd_list_iterator
{
typedef _Fwd_list_iterator<_Tp> _Self;
typedef _Fwd_list_node<_Tp> _Node;
typedef _Tp value_type;
typedef _Tp* pointer;
typedef _Tp& reference;
typedef ptrdiff_t difference_type;
typedef std::forward_iterator_tag iterator_category;
_Fwd_list_iterator() : _M_node() { }
explicit _Fwd_list_iterator(_Fwd_list_node_base* __n) : _M_node(__n) { }
reference operator*() const
{ return *static_cast<_Node*>(this->_M_node)->_M_valptr(); }
_Self& operator++()
{
_M_node = _M_node->_M_next;
return *this;
}
_Self operator++(int)
{
_Self __tmp(*this);
_M_node = _M_node->_M_next;
return __tmp;
}
bool operator==(const _Self& __x) const
{ return _M_node == __x._M_node; }
bool operator!=(const _Self& __x) const
{ return _M_node != __x._M_node; }
pointer operator->() const
{ return static_cast<_Node*>(this->_M_node)->_M_valptr(); }
_Self _M_next() const
{
if (_M_node)
return _Fwd_list_iterator(_M_node->_M_next);
else
return _Fwd_list_iterator(0);
}
_Fwd_list_node_base* _M_node;
};
忽略无关部分,我们来检查该实现对规范的遵循情况:
(1). 迭代器类型内部需定义value_type
,reference
,pointer
,difference_type
,iterator_category
内部类型。
(2). 迭代器类型应该提供前置++
,==
,!=
运算符。。
(3). 允许对迭代器iter
实例执行*iter
来访问所在位置的元素。
(4). 允许对迭代器iter
实例执行*iter=value
来设置所在位置的元素。
5.1.迭代器规范
class MyBidirectionalIterator {
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = xxx;
using difference_type = xxx;
using pointer = xxx;
using reference = xxx;
MyBidirectionalIterator(...) : ... {}
MyBidirectionalIterator& operator++() {
...
}
MyBidirectionalIterator& operator--() {
...
}
bool operator==(const MyBidirectionalIterator& other) const {
...
}
bool operator!=(const MyBidirectionalIterator& other) const {
...
}
reference operator*() const {
...
}
...
};
如上所示,对bidirectional_iterator_tag
类别的迭代器的实现要求是:
(1). 迭代器类型内部需定义value_type
,reference
,pointer
,difference_type
,iterator_category
内部类型。
a. value_type
一般表示迭代位置的元素的值类型。
b. reference
一般表示值类型的引用。
c. pointer
一般表示值的指针。
d. difference_type
,一般表示两个位置间差值。
e. iterator_category
,迭代器类别。这里应该固定为bidirectional_iterator_tag
。
(2). 迭代器类型应该提供前置++
,==
,!=
运算符。
(3). 允许对迭代器iter
实例执行*iter
来访问所在位置的元素。
(4). 允许对迭代器iter
实例执行*iter = value
来设置所在位置的元素。
(5). 迭代器类型应该提供前置--
。
和forward_iterator_tag
类别迭代器区别:
a. bidirectional_iterator_tag
其实就是forward_iterator_tag+(5)
。
5.2.标准库中实例
template<typename _Tp>
struct _List_iterator
{
typedef _List_iterator<_Tp> _Self;
typedef _List_node<_Tp> _Node;
typedef ptrdiff_t difference_type;
typedef std::bidirectional_iterator_tag iterator_category;
typedef _Tp value_type;
typedef _Tp* pointer;
typedef _Tp& reference;
_List_iterator() : _M_node() { }
explicit _List_iterator(__detail::_List_node_base* __x) : _M_node(__x) { }
reference operator*() const
{ return static_cast<_Node*>(_M_node)->_M_data; }
_Self& operator++()
{
_M_node = _M_node->_M_next;
return *this;
}
_Self operator++(int)
{
_Self __tmp = *this;
_M_node = _M_node->_M_next;
return __tmp;
}
_Self& operator--()
{
_M_node = _M_node->_M_prev;
return *this;
}
_Self operator--(int)
{
_Self __tmp = *this;
_M_node = _M_node->_M_prev;
return __tmp;
}
bool operator==(const _Self& __x) const
{ return _M_node == __x._M_node; }
bool operator!=(const _Self& __x) const
{ return _M_node != __x._M_node; }
pointer operator->() const
{ return std::__addressof(static_cast<_Node*>(_M_node)->_M_data); }
__detail::_List_node_base* _M_node;
};
忽略无关部分,我们来检查该实现对规范的遵循情况:
(1). 迭代器类型内部需定义value_type
,reference
,pointer
,difference_type
,iterator_category
内部类型。
(2). 迭代器类型应该提供前置++
。
(3). 允许对迭代器iter
实例执行*iter
来访问所在位置的元素。
(4). 允许对迭代器iter
实例执行*iter=value
来设置所在位置的元素。
(5). 迭代器类型应该提供前置--
。
6.1.迭代器规范
class MyRandomAccessIterator {
public:
using iterator_category = std::random_access_iterator_tag;
using value_type = xxx;
using difference_type = xxx;
using pointer = xxx;
using reference = xxx;
MyRandomAccessIterator(...) : ... {}
MyRandomAccessIterator& operator++() {
...
}
MyRandomAccessIterator& operator--() {
...
}
bool operator==(const MyRandomAccessIterator& other) const {
...
}
bool operator!=(const MyRandomAccessIterator& other) const {
...
}
reference operator*() const {
...
}
MyRandomAccessIterator operator+(difference_type n) const {
...
}
MyRandomAccessIterator& operator+=(difference_type n) {
...
}
MyRandomAccessIterator operator-(difference_type n) const {
...
}
MyRandomAccessIterator& operator-=(difference_type n) {
...
}
difference_type operator-(const MyRandomAccessIterator& other) const {
...
}
...
};
如上所示,对random_access_iterator_tag
类别的迭代器的实现要求是:
(1). 迭代器类型内部需定义value_type
,reference
,pointer
,difference_type
,iterator_category
内部类型。
a. value_type
一般表示迭代位置的元素的值类型。
b. reference
一般表示值类型的引用。
c. pointer
一般表示值的指针。
d. difference_type
,一般表示两个位置间差值。
e. iterator_category
,迭代器类别。这里应该固定为random_access_iterator_tag
。
(2). 迭代器类型应该提供前置++
,前置--
,==
,!=
运算符。
(3). 允许对迭代器iter
实例执行*iter
来访问所在位置的元素。
(4). 允许对迭代器iter
实例执行*iter = value
来设置所在位置的元素。
(5). 迭代器类型应该提供前置--
运算符。
(6). 迭代器类型应提供+,-,+=,-=
运算符以支持强化的前移,后移,迭代器相减。
和random_access_iterator_tag
类别迭代器区别:
a. random_access_iterator_tag
其实就是random_access_iterator_tag +(6)
。
6.2.标准库实例
template<typename _Iterator, typename _Container>
class __normal_iterator
{
protected:
_Iterator _M_current;
typedef iterator_traits<_Iterator> __traits_type;
public:
typedef _Iterator iterator_type;
typedef typename __traits_type::iterator_category iterator_category;
typedef typename __traits_type::value_type value_type;
typedef typename __traits_type::difference_type difference_type;
typedef typename __traits_type::reference reference;
typedef typename __traits_type::pointer pointer;
_GLIBCXX_CONSTEXPR __normal_iterator() : _M_current(_Iterator()) { }
explicit __normal_iterator(const _Iterator& __i) : _M_current(__i) { }
template<typename _Iter>
__normal_iterator(const __normal_iterator<_Iter, typename __enable_if<(std::__are_same<_Iter, typename _Container::pointer>::__value), _Container>::__type>& __i)
: _M_current(__i.base()) { }
reference operator*() const
{ return *_M_current; }
pointer operator->() const
{ return _M_current; }
__normal_iterator& operator++()
{
++_M_current;
return *this;
}
__normal_iterator operator++(int)
{ return __normal_iterator(_M_current++); }
__normal_iterator& operator--()
{
--_M_current;
return *this;
}
__normal_iterator operator--(int)
{ return __normal_iterator(_M_current--); }
reference operator[](const difference_type& __n) const
{ return _M_current[__n]; }
__normal_iterator& operator+=(const difference_type& __n)
{ _M_current += __n; return *this; }
__normal_iterator operator+(const difference_type& __n) const
{ return __normal_iterator(_M_current + __n); }
__normal_iterator& operator-=(const difference_type& __n)
{ _M_current -= __n; return *this; }
__normal_iterator operator-(const difference_type& __n) const
{ return __normal_iterator(_M_current - __n); }
const _Iterator& base() const
{ return _M_current; }
};
忽略无关部分,我们来检查该实现对规范的遵循情况:
(1). 迭代器类型内部需定义value_type
,reference
,pointer
,difference_type
,iterator_category
内部类型。
(2). 迭代器类型应该提供前置++
。
(3). 允许对迭代器iter
实例执行*iter
来访问所在位置的元素。
(4). 允许对迭代器iter
实例执行*iter=value
来设置所在位置的元素。
(5). 迭代器类型应该提供前置--
。
(6). 迭代器类型应该提供+,+=,-,-=
以支持强化的前移,后移,迭代器相减。