`
aspnetwinform
  • 浏览: 84726 次
  • 性别: Icon_minigender_2
  • 来自: 武汉
社区版块
存档分类
最新评论

从零开始学C++之STL(十):迭代器适配器{(插入迭代器back_insert_iterator)、IO流迭代器(istream_iterator、ostream_iterator)}

 
阅读更多

一、迭代器适配器

反向迭代器

插入迭代器

IO流迭代器


其中反向迭代器可以参考以前的文章


二、插入迭代器

插入迭代器实际上是一个输出迭代器(*it=; ++)


back_insert_iterator
back_inserter


front_insert_iterator
front_inserter


先来看示例:

C++ Code
<nobr>1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br> 14<br> 15<br> 16<br> 17<br> 18<br> 19<br> 20<br> 21<br> 22<br> 23<br> 24<br> 25<br> 26<br> 27<br> 28<br> 29<br> 30<br> 31<br> 32<br> 33<br> 34<br> 35<br> 36<br> 37<br> 38<br></nobr>
#include<iostream>
#include<vector>
#include<algorithm>

usingnamespacestd;

voidShowVec(constvector<int>&v)
{
for(vector<int>::const_iteratorit=v.begin();it!=v.end();++it)
{
cout<<*it<<'';
}
cout<<endl;
}
intmain(void)
{
inta[]={1,2,3,4,5};
vector<int>v(a,a+5);
vector<int>v2;

back_insert_iterator<vector<int>>bii(v);
//*bii=6;
bii=6;
ShowVec(v);

back_insert_iterator<vector<int>>bii2(v2);
copy(v.begin(),v.end(),bii2);
ShowVec(v2);

back_inserter(v)=7;
ShowVec(v);

copy(v.begin(),v.end(),back_inserter(v2));
ShowVec(v2);


return0;
}

查看back_insert_iterator 类的定义:

C++ Code
<nobr>1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br> 14<br> 15<br> 16<br> 17<br> 18<br> 19<br> 20<br> 21<br> 22<br> 23<br> 24<br> 25<br> 26<br> 27<br> 28<br> 29<br> 30<br> 31<br> 32<br> 33<br> 34<br> 35<br> 36<br> 37<br> 38<br> 39<br> 40<br> 41<br> 42<br> 43<br> 44<br> 45<br> 46<br> 47<br></nobr>
//TEMPLATECLASSback_insert_iterator
template<class_Container>
classback_insert_iterator
:public_Outit
{
//wrappushestobackofcontainerasoutputiterator
public:
typedef_Containercontainer_type;
typedeftypename_Container::referencereference;

typedef_Range_checked_iterator_tag_Checked_iterator_category;

explicitback_insert_iterator(_Container&_Cont)
:container(&_Cont)
{
//constructwithcontainer
}

back_insert_iterator<_Container>&operator=(
typename_Container::const_reference_Val)
{
//pushvalueintocontainer
container->push_back(_Val);
return(*this);
}

back_insert_iterator<_Container>&operator*()
{
//pretendtoreturndesignatedvalue
return(*this);
}

back_insert_iterator<_Container>&operator++()
{
//pretendtopreincrement
return(*this);
}

back_insert_iterator<_Container>operator++(int)
{
//pretendtopostincrement
return(*this);
}

protected:
_Container*container;//pointertocontainer
};

类内部的成员container 保存的是指向容器的指针,重载了*, ++, = 等运算符,* 和 ++ 返回的都是迭代器本身,主要看 赋值运算符:


container->push_back(_Val); 即调用了容器的push_back 函数, 所以可以直接写 bii = 6; 即将6压入容器末尾。程序中还调用了copy


函数,回顾copy 源码,主要是以下代码:


for(;_First!=_Last;++_Dest,++_First)



*_Dest=*_First;


其中,_First 和 _Last 分别是v.begin() 和 v.end(), _Dest 是 bii2,上面也说了,*_Dest 返回的是自身,而且++_Dest 返回的也是自


身,从_First 遍历到 _Last ,调用back_insert_iterator 类的operator=,即不断地执行container->push_back(_Val); 容器的元素位置会


自动移动。


再来看back_inserter 函数:

C++ Code
<nobr>1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br></nobr>
//TEMPLATEFUNCTIONback_inserter
template<class_Container>inline
back_insert_iterator<_Container>back_inserter(_Container&_Cont)
{
//returnaback_insert_iterator
return(std::back_insert_iterator<_Container>(_Cont));
}

实际上返回的也是一个back_insert_iterator 对象,所以能直接替换掉bii2。


当然了,与back 配对的就是front,back 是末尾插入,front 是头端插入,需要注意的是front_insert_iterator 的operator= 调用了


push_front 函数,故如vector 是没有实现push_front 的,不能使用front_insert_iterator ,而list 和 deque 是可以使用的。


示例代码如下:

C++ Code
<nobr>1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br> 14<br> 15<br> 16<br> 17<br> 18<br> 19<br> 20<br> 21<br> 22<br> 23<br> 24<br> 25<br> 26<br> 27<br> 28<br> 29<br> 30<br></nobr>
#include<iostream>
#include<vector>
#include<list>
#include<algorithm>

usingnamespacestd;

voidShowList(constlist<int>&v)
{
for(list<int>::const_iteratorit=v.begin();it!=v.end();++it)
{
cout<<*it<<'';
}
cout<<endl;
}

intmain(void)
{
inta[]={1,2,3,4,5};
list<int>l(a,a+5);
list<int>ll;

front_insert_iterator<list<int>>fii(l);
fii=0;
ShowList(l);

copy(l.begin(),l.end(),front_inserter(ll));
ShowList(ll);
return0;
}


三、IO流迭代器


输出流迭代器(ostream_iterator)


*it=; ++


输入流迭代器(istream_iterator)

=*it; ->; ++; ==; !=


直接来看示例代码:

C++ Code
<nobr>1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br> 14<br> 15<br> 16<br> 17<br> 18<br> 19<br> 20<br></nobr>
#include<iostream>
#include<vector>
#include<list>
#include<algorithm>

usingnamespacestd;

intmain(void)
{
vector<int>v;

//copyfromcintovector
copy(istream_iterator<int>(cin),istream_iterator<int>(),back_inserter(v));

//copyfromvectortocout
copy(v.begin(),v.end(),ostream_iterator<int>(cout,""));
cout<<endl;

return0;
}

首先来看istream_iterator 的源码:

C++ Code
<nobr>1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br> 14<br> 15<br> 16<br> 17<br> 18<br> 19<br> 20<br> 21<br> 22<br> 23<br> 24<br> 25<br> 26<br> 27<br> 28<br> 29<br> 30<br> 31<br> 32<br> 33<br> 34<br> 35<br> 36<br> 37<br> 38<br> 39<br> 40<br> 41<br> 42<br> 43<br> 44<br> 45<br> 46<br> 47<br> 48<br> 49<br> 50<br> 51<br> 52<br> 53<br> 54<br> 55<br> 56<br> 57<br> 58<br> 59<br> 60<br> 61<br> 62<br> 63<br> 64<br> 65<br> 66<br></nobr>
//TEMPLATECLASSistream_iterator
template<class_Ty,
class_Elem=char,
class_Traits=char_traits<_Elem>,
class_Diff=ptrdiff_t>
classistream_iterator
:publiciterator<input_iterator_tag,_Ty,_Diff,
const_Ty*,const_Ty&>
{
//wrap_Tyextractsfrominputstreamasinputiterator
typedefistream_iterator<_Ty,_Elem,_Traits,_Diff>_Myt;
public:
typedef_Elemchar_type;
typedef_Traitstraits_type;
typedefbasic_istream<_Elem,_Traits>istream_type;

#if_SECURE_SCL
typedef_Range_checked_iterator_tag_Checked_iterator_category;
#endif

istream_iterator()
:_Myistr(0)
{
//constructsingulariterator
}

istream_iterator(istream_type&_Istr)
:_Myistr(&_Istr)
{
//constructwithinputstream
_Getval();
}

const_Ty&operator*()const
{
//returndesignatedvalue

return(_Myval);
}

const_Ty*operator->()const
{
//returnpointertoclassobject
return(&**this);
}

_Myt&operator++()
{
//preincrement

_Getval();
return(*this);
}


protected:
void_Getval()
{
//geta_Tyvalueifpossible
if(_Myistr!=0&&!(*_Myistr>>_Myval))
_Myistr=0;
}

istream_type*_Myistr;//pointertoinputstream
_Ty_Myval;//lookaheadvalue(validif_Myistrisnotnull)
};

上面只截取了部分用上的源码,istream_iterator 类有两个成员,一个是输入流对象指针,一个是输入的值,如


istream_iterator<int>(cin) 调用构造函数,初始化_Myistr,且通过函数_Getval() 初始化_Myval,_Getval() 调用输入流的


operator>> 将键盘输入的值赋予_Myval。而istream_iterator<int>() 呢初始化_Myistr 为0,此时_Myval 被忽略。


回顾copy 源码,主要是以下代码:


for(;_First!=_Last;++_Dest,++_First)



*_Dest=*_First;


此时_First 和 _Last 是istream_iterator<int> 类型,_Dest是back_insert_iterator 类型,而判断_First 和 _Last 是否相等,其实


operator != 里面是判断它们的成员指针_Myistr 是否相等,在_Getval 函数可以看到,当我们输入错误(类型不匹配)或者ctrl+z,


istream_iterator<int>(cin) 的_Myistr 被置为0,此时本来istream_iterator<int>() 的_Myistr 就为0,故相等,不再继续执行下去。


如果不等,即输入正确的话,*First 调用istream_iterator 类的operator* 直接返回_Myval ,接着调用back_insert_iterator 类的


operator=,即调用container 的push_back ,将_Myval 压入容器。++_Dest 是没什么效果的,而++_First 在istream_iterator 类的


operator++ 中会继续调用_Getval,即继续获得键盘输入覆盖_Myval。


再来看ostream_iterator 的源码:

C++ Code
<nobr>1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br> 14<br> 15<br> 16<br> 17<br> 18<br> 19<br> 20<br> 21<br> 22<br> 23<br> 24<br> 25<br> 26<br> 27<br> 28<br> 29<br> 30<br> 31<br> 32<br> 33<br> 34<br> 35<br> 36<br> 37<br> 38<br> 39<br> 40<br> 41<br> 42<br> 43<br> 44<br> 45<br> 46<br></nobr>
//TEMPLATECLASSostream_iterator
template<class_Ty,
class_Elem=char,
class_Traits=char_traits<_Elem>>
classostream_iterator
:public_Outit
{//wrap_Tyinsertstooutputstreamasoutputiterator
public:
typedef_Elemchar_type;
typedef_Traitstraits_type;
typedefbasic_ostream<_Elem,_Traits>ostream_type;

#if_SECURE_SCL
typedef_Range_checked_iterator_tag_Checked_iterator_category;
#endif

ostream_iterator(ostream_type&_Ostr,
const_Elem*_Delim=0)
:_Myostr(&_Ostr),_Mydelim(_Delim)
{//constructfromoutputstreamanddelimiter
}

ostream_iterator<_Ty,_Elem,_Traits>&operator=(const_Ty&_Val)
{//insertvalueintooutputstream,followedbydelimiter
*_Myostr<<_Val;
if(_Mydelim!=0)
*_Myostr<<_Mydelim;

return(*this);
}

ostream_iterator<_Ty,_Elem,_Traits>&operator*()
{//pretendtoreturndesignatedvalue
return(*this);
}

ostream_iterator<_Ty,_Elem,_Traits>&operator++()
{//pretendtopreincrement
return(*this);
}

protected:

const_Elem*_Mydelim;//pointertodelimiterstring(NB:notfreed)
ostream_type*_Myostr;//pointertooutputstream
};

ostream_iterator 类也有两个成员,一个是输出流对象指针,一个是字符串指针,看上面的copy 代码,此时_First 和 _Last


分别是v.begin() 和 v.end(),_Dest是ostream_iterator<int>类型,*_Dest 返回自身,++_Dest 也返回自身,而在operator= 函数中


*_Myostr << _Val;


if (_Mydelim != 0)


*_Myostr << _Mydelim;


即判断如果还有传入字符串,则在输出元素值之后,还伴随着字符串的输出。所以示例代码中的输出是伴随着空格的。


参考:

C++ primer 第四版
Effective C++ 3rd
C++编程规范

分享到:
评论

相关推荐

    面向对象方法(STL_analysis)of_Iterator迭代器

    面向对象方法(STL_analysis)of_Iterator迭代器,这个文档对这进行了详细介绍,供参考!

    C++ STL 迭代器 入门

    关于 C++ STL 迭代器 的最佳入门教程之一。 轻松、幽默、干脆、一看就会!却不乏C++编程思想之启发!

    C++ STL开发技术导引(第5章)

    第五篇 C++ STL迭代器技术 第25章 输入输出流迭代器 424 25.1 输入流迭代器 424 25.2 输出流迭代器 426 25.3 本章小结 427 第26章 插入/反向/存储迭代器 428 26.1 向前插入迭代器 428 26.2 向后插入...

    C++进阶STL适配器总结1

    }3. 插入迭代器适配器|函数|作用||:-||insert_iterator&lt;Container&gt; inserter (Container& x, Itera

    STL.rar_STL_STL PPT_iterator_stl p

    stl的入门ppt 很好用哦,分为导入 STL的概念与组成 Iterator(迭代器) Container(容器) Algorithm(算法) Adaptors(配接器)

    C++迭代器介绍(iterator、const_iterator、reverse_interator、const_reverse_interator)

    概念:C++的一种机制,用来遍历标准模板库容器中的元素,是一种”智能”指针 一、迭代器的特点 迭代器是一种智能指针,具有遍历复杂数据结构的能力 ... 随机访问迭代器:是一般的迭代器,既可以随机的实现跳

    Qt5开发及实例-CH203.rar,Qt5使用STL风格迭代器的代码

    实例CH203,使用STL风格迭代器。 (a) list.insert(list.end(),j):使用QList&lt;T&gt;::insert()函数插入10个整数值。此函数有两个参数:第一个参数是QList&lt;T&gt;::iterator类型,表示在该列表项之前插入一个新的列表项(使用...

    C++ STL 开发技术导引(第6章)

    第五篇 C++ STL迭代器技术 第25章 输入输出流迭代器 424 25.1 输入流迭代器 424 25.2 输出流迭代器 426 25.3 本章小结 427 第26章 插入/反向/存储迭代器 428 26.1 向前插入迭代器 428 26.2 向后插入...

    C++STL学习经典

    STL有三大核心部分:容器(Container)、算法(Algorithms)、迭代器(Iterator),容器适配器(container adaptor),函数对象(functor),除此之外还有STL其他标准组件。

    仿std&&list;的iterator迭代器

    仿std&&list;的iterator迭代器,有助于加深对stl中各种封装类的理解

    STL源码剖析.pdg

    3.4.5 迭代器相应型别之五iterator_category 092 以advanced() 为例 093 消除 "单纯传递调用函数" 097 以distance() 为例 098 3.5 std::iterator class 的保证 099 3.6 iterator相关源码完整重列 101 3.7 sgi ...

    STL 源码剖析(侯捷先生译著)

    3.4.5 迭代器相应型别之五iterator_category 092 以advanced() 为例 093 消除 "单纯传递调用函数" 097 以distance() 为例 098 3.5 std::iterator class 的保证 099 3.6 iterator相关源码完整重列 101 3.7 SGI ...

    c++stl标准库源码

    c++ stl The Standard Template Library, 容器(Container) 迭代器(Iterator) 算法(Algorithm)仿函数(Function object)迭代适配器(Adaptor)空间配制器(allocator)

    iterator.zip

    STL iterator相关代码

    stl_interfaces:用于定义迭代器的C ++ 14和更高版本的CRTP模板

    对于迭代器部分-如果您需要编写迭代器,则iterator_interface会将其设置为: struct repeated_chars_iterator { using value_type = char ; using difference_type = std:: ptrdiff_t ; using pointe

    C++ STL开发技术导引(第3章)

    第五篇 C++ STL迭代器技术 第25章 输入输出流迭代器 424 25.1 输入流迭代器 424 25.2 输出流迭代器 426 25.3 本章小结 427 第26章 插入/反向/存储迭代器 428 26.1 向前插入迭代器 428 26.2 向后插入...

    STL学习总结

    关于STL学习的总结: STL就是Standard Template Library,标准模板库。这可能是一个历史上最令人兴奋...大体上包括container(容器)、algorithm(算法)和iterator(迭代器),容器和算法通过迭代器可以进行无缝连接。

    effective stl stl 技巧

    迭代器 条款26:尽量用iterator代替const_iterator,reverse_iterator和const_reverse_iterator 条款27:用distance和advance把const_iterator转化成iterator 条款28:了解如何通过reverse_iterator的base得到...

    自编MStirng(类似std::string)以及配套的4种iterators

    编写它的目的不是为了使用,而是为了熟悉stl算法及迭代器的原理。其中MString仅支持简单的基本操作,但在此基础上扩展其他功能已经很容易。主要精力放在了iterator的编写上,iterator开发了全部功能,使用了模板,...

    C++设计模式之迭代器模式(Iterator)

    迭代器在STL运用广泛,类似容器的迭代已经成为其重要特性,而迭代器模式则是利用迭代器概念进行的抽象运用,迭代器模式运用广泛和有用,因为其能够不考虑数据的存储方式,而是直接面对数据进行迭代,也就是说我们...

Global site tag (gtag.js) - Google Analytics