技术在于交流、沟通,本文为博主原创文章转载请注明出处并保持作品的完整性

这次主要介绍一下迭代器适配器.以reverse_iterator(反向迭代器),insert_iterator(插入迭代器),ostream_iterator(输出迭代器)迭代器和算法中的copy函数做参考

迭代器适配器主要运用包含及操作符重载实现(主要操作符重载有operator*,operator=,operator++,operator--)

其实本节主要就是介绍运算符重载


1.reverse_iterator反向迭代器的实现

下面是reverse_iterator的源码

template<typename _Iterator>
class reverse_iterator
: public iterator<typename iterator_traits<_Iterator>::iterator_category,
typename iterator_traits<_Iterator>::value_type,
typename iterator_traits<_Iterator>::difference_type,
typename iterator_traits<_Iterator>::pointer,
typename iterator_traits<_Iterator>::reference>
{
protected:
_Iterator current; typedef iterator_traits<_Iterator> __traits_type; public:
typedef _Iterator iterator_type;
typedef typename __traits_type::difference_type difference_type;
typedef typename __traits_type::pointer pointer;
typedef typename __traits_type::reference reference; /**
* The default constructor value-initializes member @p current.
* If it is a pointer, that means it is zero-initialized.
*/
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 235 No specification of default ctor for reverse_iterator
reverse_iterator() : current() { } /**
* This %iterator will move in the opposite direction that @p x does.
*/
explicit
reverse_iterator(iterator_type __x) : current(__x) { } /**
* The copy constructor is normal.
*/
reverse_iterator(const reverse_iterator& __x)
: current(__x.current) { } /**
* A %reverse_iterator across other types can be copied if the
* underlying %iterator can be converted to the type of @c current.
*/
template<typename _Iter>
reverse_iterator(const reverse_iterator<_Iter>& __x)
: current(__x.base()) { } /**
* @return @c current, the %iterator used for underlying work.
*/
iterator_type
base() const
{ return current; } /**
* @return A reference to the value at @c --current
*
* This requires that @c --current is dereferenceable.
*
* @warning This implementation requires that for an iterator of the
* underlying iterator type, @c x, a reference obtained by
* @c *x remains valid after @c x has been modified or
* destroyed. This is a bug: http://gcc.gnu.org/PR51823
*/
reference
operator*() const
{
_Iterator __tmp = current;
return *--__tmp;
} /**
* @return A pointer to the value at @c --current
*
* This requires that @c --current is dereferenceable.
*/
pointer
operator->() const
{ return &(operator*()); } /**
* @return @c *this
*
* Decrements the underlying iterator.
*/
reverse_iterator&
operator++()
{
--current;
return *this;
} /**
* @return The original value of @c *this
*
* Decrements the underlying iterator.
*/
reverse_iterator
operator++(int)
{
reverse_iterator __tmp = *this;
--current;
return __tmp;
} /**
* @return @c *this
*
* Increments the underlying iterator.
*/
reverse_iterator&
operator--()
{
++current;
return *this;
} /**
* @return A reverse_iterator with the previous value of @c *this
*
* Increments the underlying iterator.
*/
reverse_iterator
operator--(int)
{
reverse_iterator __tmp = *this;
++current;
return __tmp;
} /**
* @return A reverse_iterator that refers to @c current - @a __n
*
* The underlying iterator must be a Random Access Iterator.
*/
reverse_iterator
operator+(difference_type __n) const
{ return reverse_iterator(current - __n); } /**
* @return *this
*
* Moves the underlying iterator backwards @a __n steps.
* The underlying iterator must be a Random Access Iterator.
*/
reverse_iterator&
operator+=(difference_type __n)
{
current -= __n;
return *this;
} /**
* @return A reverse_iterator that refers to @c current - @a __n
*
* The underlying iterator must be a Random Access Iterator.
*/
reverse_iterator
operator-(difference_type __n) const
{ return reverse_iterator(current + __n); } /**
* @return *this
*
* Moves the underlying iterator forwards @a __n steps.
* The underlying iterator must be a Random Access Iterator.
*/
reverse_iterator&
operator-=(difference_type __n)
{
current += __n;
return *this;
} /**
* @return The value at @c current - @a __n - 1
*
* The underlying iterator must be a Random Access Iterator.
*/
reference
operator[](difference_type __n) const
{ return *(*this + __n); }
};

我们主要以几个比较明显的表示其适配器特征的函数为例

template<typename _Iterator>
class reverse_iterator
: public iterator<typename iterator_traits<_Iterator>::iterator_category,
typename iterator_traits<_Iterator>::value_type,
typename iterator_traits<_Iterator>::difference_type,
typename iterator_traits<_Iterator>::pointer,
typename iterator_traits<_Iterator>::reference>
{
protected:
_Iterator current;//对应的正向迭代器 typedef iterator_traits<_Iterator> __traits_type;//迭代器萃取机 public:
typedef _Iterator iterator_type;//逆向迭代器的5中associated types 和其他迭代器相同
typedef typename __traits_type::difference_type difference_type;
typedef typename __traits_type::pointer pointer;
typedef typename __traits_type::reference reference; //构造函数
reverse_iterator() : current() { }
explicit
reverse_iterator(iterator_type __x) : current(__x) { }
reverse_iterator(const reverse_iterator& __x)
: current(__x.current) { } //取出对应的正向迭代器
iterator_type
base() const
{ return current; } //关键点在这里, *操作取值,取对应正向迭代器的上一位
reference
operator*() const
{
_Iterator __tmp = current;
return *--__tmp;
} pointer
operator->() const
{ return &(operator*()); } //前进变后退 后退变前进
reverse_iterator&
operator++()
{
--current;
return *this;
} reverse_iterator
operator++(int)
{
reverse_iterator __tmp = *this;
--current;
return __tmp;
} reverse_iterator&
operator--()
{
++current;
return *this;
} reverse_iterator
operator--(int)
{
reverse_iterator __tmp = *this;
++current;
return __tmp;
} reverse_iterator
operator+(difference_type __n) const
{ return reverse_iterator(current - __n); } reverse_iterator&
operator+=(difference_type __n)
{
current -= __n;
return *this;
} reverse_iterator
operator-(difference_type __n) const
{ return reverse_iterator(current + __n); } reverse_iterator&
operator-=(difference_type __n)
{
current += __n;
return *this;
} reference
operator[](difference_type __n) const
{ return *(*this + __n); }
};

下面是反向迭代器的起点和终点函数及图解

reverse_iterator rbegin()
{
return reverse_iterator(end());
} reverse_iterator rend()
{
return reverse_iterator(begin());
}

总结 反向迭代器,它包含其正向迭代器,使用重载其原来的operator*,operator++等操作实现其反向功能


2.insert_iterator

首先看一下算法中的copy函数源码(G2.9)

template<class InputIterator, class OutputIterator>
OutputIterator copy(InputIterator first, InputIterator last, OutputIterator result)
{
while (first!=last)
{
*result = * first;
++result;
++first;
}
}

注意copy()函数中没有申请新的内存,采取的方式是直接赋值,那么当内存不够使用时,调用copy函数会报错

namespace wzj009 {

    void test_Insert_Iterator()
{
int myArray[] = {,,,,,,}; vector<int> v1;
v1.resize();//申请内存为6 copy(myArray, myArray + , v1.begin());//copy7个元素过来导致越界 for(auto i : v1)
{
cout << i << endl;
}
}
}

现在我们看下面这段代码是够能够编译通过

namespace wzj010 {

    void test_Insert_Iterator()
{
int myArray[] = {,,,,,,}; vector<int> v1;
v1.resize(); copy(myArray, myArray + , inserter(v1,v1.begin())); for(auto i : v1)
{
cout << i << endl;
}
}
}

我们从copy的源码中可以看得出,它的每一个方法都是写死的,那么为什么这几就能编译通过,这份功劳应该归功于运算符重载,因为insert方法会调用到insert_iterator,而insert_iterator重载了operator=,进而实现了该功能

我们看一下insert_iterator的源码

template<typename _Container>
class insert_iterator
: public iterator<output_iterator_tag, void, void, void, void>
{
protected:
_Container* container;
typename _Container::iterator iter; public:
typedef _Container container_type; insert_iterator(_Container& __x, typename _Container::iterator __i)
: container(&__x), iter(__i) {} …
insert_iterator&
operator=(const typename _Container::value_type& __value)
{
iter = container->insert(iter, __value);
++iter;
return *this;
} insert_iterator&
operator=(typename _Container::value_type&& __value)//关键点在这里,它重载了operator= 使copy函数中的 *result = * first; 调用这里的operator函数
{
iter = container->insert(iter, std::move(__value));
++iter;
return *this;
}

}
  template<typename _Container, typename _Iterator>
inline insert_iterator<_Container>
inserter(_Container& __x, _Iterator __i)
{
return insert_iterator<_Container>(__x,
typename _Container::iterator(__i));
}//这个函数使insert调用insert_iterator

虽然运算符重载有时使我们很难读懂代码,但其功能是非常强大的


3 ostream_iterator

看下面代码

namespace wzj011 {

    void test_ostream_iterator()
{
vector<int> v;
for(int i = ;i<; i++) v.push_back(i*);
std::ostream_iterator<int> out_it(std::cout, "-");//将将std::cout绑定在out_it,并且输出每个元素时加以"-"
copy(v.begin(),v.end(),out_it);
}
}

我紧紧是将v copy给 out_it 却输出了out_it内的元素, 那么此时我的copy功能实现了其std::cout,那么copy函数这个功能任然要归功于函数重载

template<typename _Tp, typename _CharT = char,
typename _Traits = char_traits<_CharT> >
class ostream_iterator
: public iterator<output_iterator_tag, void, void, void, void>
{

private:
ostream_type* _M_stream;
const _CharT* _M_string; public:
/// Construct from an ostream.
ostream_iterator(ostream_type& __s) : _M_stream(&__s), _M_string() {}//std::ostream_iterator<int> out_it(std::cout, “-“)将_M_stream 绑定为std::cout “-“赋值给_M_string ostream_iterator(ostream_type& __s, const _CharT* __c)
: _M_stream(&__s), _M_string(__c) { } /// Copy constructor.
ostream_iterator(const ostream_iterator& __obj)
: _M_stream(__obj._M_stream), _M_string(__obj._M_string) { } /// Writes @a value to underlying ostream using operator<<. If
/// constructed with delimiter string, writes delimiter to ostream.
ostream_iterator&
operator=(const _Tp& __value)//
{
__glibcxx_requires_cond(_M_stream != ,
_M_message(__gnu_debug::__msg_output_ostream)
._M_iterator(*this));
*_M_stream << __value;//将value传递给_M_stream 使其作出输出动作
if (_M_string) *_M_stream << _M_string;
return *this;
}

};

以上的三种迭代器适配器都非常好理解,更重要的是在于我们要理解他的设计理念,运算重载功能非常强大,要好好利用

参考侯捷<<STL源码剖析>>

STL标准库-迭代器适配器的更多相关文章

  1. STL标准库-容器适配器

    技术在于交流.沟通,本文为博主原创文章转载请注明出处并保持作品的完整性 上一节介绍了仿函数适配器,这节主要介绍容器适配器和迭代器适配器的概念,其实容器适配器和迭代器其适配器就是封装了一些其他class ...

  2. STL标准库-迭代器

    技术在于交流.沟通,本文为博主原创文章转载请注明出处并保持作品的完整性 本节主要介绍STL六大部件中的Iterators迭代器. 在语言方面讲,容器是一个class template, 算法是一个仿函 ...

  3. STL标准库-容器-set与multiset

    技术在于交流.沟通,转载请注明出处并保持作品的完整性. set与multiset关联容器 结构如下 set是一种关联容器,key即value,value即key.它是自动排序,排序特点依据key se ...

  4. STL标准库-算法-常用算法

    技术在于交流.沟通,本文为博主原创文章转载请注明出处并保持作品的完整性 介绍11种STL标准库的算法,从这11种算法中总结一下算法的基本使用 1.accumulate() 累加 2.for_each( ...

  5. STL标准库-容器-deque

    技术在于交流.沟通,本文为博主原创文章转载请注明出处并保持作品的完整性. deque双向开口可进可出的容器 我们知道连续内存的容器不能随意扩充,因为这样容易扩充别人那去 deque却可以,它创造了内存 ...

  6. STL标准库-容器-vector

    技术在于交流.沟通,本文为博主原创文章转载请注明出处并保持作品的完整性. 向量容器vector是一个动态数组,内存连续,它是动态分配内存,且每次扩张的原来的二倍. 他的结构如下 一 定义 vector ...

  7. C++STL标准库学习笔记(五)set

    前言: 在这个笔记中,我把大多数代码都加了注释,我的一些想法和注解用蓝色字体标记了出来,重点和需要关注的地方用红色字体标记了出来,这一篇后面主要都是我的记录了,为了防止大片蓝色字体出现,后面就不改蓝色 ...

  8. C++STL标准库学习笔记(三)multiset

    C++STL标准库学习笔记(三)multiset STL中的平衡二叉树数据结构 前言: 在这个笔记中,我把大多数代码都加了注释,我的一些想法和注解用蓝色字体标记了出来,重点和需要关注的地方用红色字体标 ...

  9. c/c++ 标准库 迭代器(iterator)

    c/c++ 标准库 迭代器 begin和end运算符返回的具体类型由对象是否是常量决定,如果对象是常量,begin和end返回const_iterator:如果对象不是常量,返回iteraotor 1 ...

随机推荐

  1. VisualStudio使用技巧及快捷键

    1. 怎样调整代码排版的格式? 选择:编辑—>高级—>设置文档的格式或编辑—>高级—>设置选中代码的格式. 格式化cs代码:Ctrl+k+f 格式化aspx代码:Ctrl+k+ ...

  2. 用python生成器实现杨辉三角

    先看杨辉三角的形态: 1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 1 5 10 10 5 1 上学的时候大多是用c语言的两层for循环在实现,现在我们尝试用生成器来实现. 先说思路:我 ...

  3. c语言 数组合并

    #include<stdio.h> int main() { int m,n,i,j,k; printf("Enter no. of elements in array1:\n& ...

  4. shell 求幂

    $ let i=** $ echo $i $ ((i=**)) $ echo $i $ echo "5^2" | bc

  5. SQLServer 大小写转换

    SQLServer中小转大也是同样的默认快捷键,大转小换成L了 1.小写转换大写  Ctrl + shift + U 2.大写转换小写  Ctrl + shift + L

  6. STL_容器共通能力

    1. 来自教程: ◆ 所有容器提供的都是值(value)语意,而非引用(reference)语意.容器执行插入元素的操作时,内部实施拷贝动作.所以STL容器内存储的元素必须能够被拷贝(必须提供拷贝构造 ...

  7. 《剑指offer》第四十题(最小的k个数)

    // 面试题40:最小的k个数 // 题目:输入n个整数,找出其中最小的k个数.例如输入4.5.1.6.2.7.3.8 // 这8个数字,则最小的4个数字是1.2.3.4. #include < ...

  8. 从996到ICU——我们终将被自我厌恶

    自从996.icu在github上收获了18万点赞以来,超时工作,超负荷劳动似乎成了天下所有“无产阶级者”的共同点.对于这样的剥削制度,我想再多的批评和抨击都不为过.但是今天我想说3个小故事,只为引起 ...

  9. 启动tomcat一闪而过问题调试并解决

    之前一直用myelise+tomcat启动项目很正常,今天在尝试用绿色版tomcat8时,点击startup.bat文件时,一闪而过,tomcat未正常启动,也无法看到错误信息.搜索网络查找到调试方法 ...

  10. MySQL函数GROUP_CONCAT() 实现多条数据合并

    group_concat()会计算哪些行属于同一组,将属于同一组的列显示出来,group by指定的列进行分组. 例如: -- 根据物流订单id查询所有物流订单,车源订单,车辆信息(多条数据合并为一条 ...