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

这次主要介绍一下迭代器适配器.以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. MongoDB树形结构表示法

    http://docs.mongodb.org/manual/tutorial/model-tree-structures/ MongoDB五种树形结构表示法 第一种:父链接结构 db.categor ...

  2. oadrunner11录制手机app脚本

    oadrunner11录制手机app视频:http://pan.baidu.com/s/1bnc4cHL 注意点: 1.手机和loadrunner安装的电脑必须在同一网段2.视频的www.baidu. ...

  3. shell 余弦值转角度

    范例:余弦值转角度 用 bc -l 计算,可以获得高精度: $ export cos=0.996293; echo "scale=100; a(sqrt(1-$cos^2)/$cos)*18 ...

  4. resource not found : rosbridge_server

    1.放到src下,改名字为rosbridge_server,编译catkin_make git clone https://github.com/RobotWebTools/rosbridge_sui ...

  5. Jmeter 抓app包 抓到一半不好用了

    错误描述: java.net.ConnectException: Connection refused (Connection refused) at java.net.PlainSocketImpl ...

  6. zlib__ZC

    官网:http://www.zlib.net/ ,所有版本下载:http://www.zlib.net/fossils/ ZC: 我下载的是 zlib-1.2.3.tar.gz 和 zlib-1.2. ...

  7. linux下模拟FTP服务器(笔记)

    要在linux下做一个模仿ftp的小型服务器,后来在百度文库中找到一份算是比较完整的实现,就在原代码一些重要部分上备注自己的理解(可能有误,千万不要轻易相信). 客户端: 客户端要从服务器端中读取数据 ...

  8. Codeforces 496C - Removing Columns

    496C - Removing Columns 思路:暴力,用vis标记数组实时记录一下之前的行i+1和上一行i否全相等,false表示全相等. 代码: #include<bits/stdc++ ...

  9. 新的请求方式 fetch和axios

    参考链接:https://www.javascriptcn.com/read-5840.html axios使用文档: https://www.kancloud.cn/yunye/axios/2348 ...

  10. 富文本编辑器layedit,调用setContent方法会报错

    需要把layedit.js里的setContent 函数的 layedit.sync(index)); 改成 this.sync(index));