C++ iostream 迭代器 STL

iostream迭代器
iostream迭代器的构造函数
istream_iterator<T> in(strm);  创建从输入流strm中读取T类型对象的istream_iterator对象
istream_iterator<T> in;  istream_iterator对象的超出末端迭代器
ostream_iterator<T> in(strm);  创建将T类型的对象写到输出流strm的ostream_iterator对象
ostream_iterator<T> in(strm,delim);  创建将T类型的对象写到输出流strm的ostream_iterator 对象,在写入过程中使用delim作为元素的分隔符。delim是以空字符结束的字符数组

还有比较两个istream迭代器是否相等。而ostream迭代器则不提供比较运算
it1==it2  比较两个istream_iterator对象是否相等(不等)。迭代器读取的必须是相同的类型。
it1!=it2  如果两个迭代器都是end值,则它们相等。对于两个都不指向流结束位置的迭代器,如果 它们使用同一个输入流构造,则它们也相等

*it  返回从流中读取的值。
it->mem  是(*it).mem的同义词。返回从流中读取的对象的mem成员
++it  通过使用元素类型提供的>>操作符从输入流中读取下一个元素值。使迭代器向前移动。通常

it++  前缀版本使迭代器在流中向前移动,并返回对加1后的迭代器的引用。而后缀版本使迭代器在 流中向前移动后,返回原值。



1、流迭代器的定义。。任何已定义输入操作符(>>)的类型都可以定义istream_iterator。任何已定义输出操作符(<<)的类型也可定义ostream_iterator。在创建流迭代器时,必须指定迭代器所读写的对象类型

istream_iterator<int> cin_it(cin>;
istream_iterator<int> end_of_stream;
ofstream outfile;
ostream_iteratro<Sales_item> output(outfile," ");
ostream_iterator对象必须与特定的流绑定在一起。在创建istream_iterator时,可直接将它绑定到一个流上。另一种方法是在创建进不提供实参,则该迭代器指向超出末端位置。

ostream_iterator不提供超出末端迭代器。在创建ostream_iterator对象时,可提供第二个实参,指定将元素写入输出流时使用的分隔符。分隔符必须是C风格字符串。因为它是C风格字符串,所以

必须以空字符结束;否则其行为将是未定义的。。



2、istream_iterator对象上的操作
构造与流绑定在一起的istream_iterator对象时,将对迭代器定位,以便第一次对该迭代器进行解引用时即可从流中读取第一个值。

istream_iterator<int> in_iter(cin);
istream_iterator<int> eof;
while(in_iter!=eof)
      vec.push_back(*in_iter++);
这个循环从cin中读取int型数据,并将读入的内容保存在vec中。每次循环都检查in_iter是否为eof其中eof迭代器定义为空的istream_iterator对象,用作结束迭代器。绑在流上的迭代器在遇到文件结束或错误时。将等于结束迭代器的值。

push_back的实参使用解引用和后自增操作符。自增运算的结果将是解引用运算的操作数。对istream_iterator对象做自增运算使该迭代器在流中向前移动。然而,使用后自增运算的表达式。

其结果是迭代器原来的值。自增的效果是使迭代器在流中移动到下一个值,但返回前一个值的迭代器。。可以这样重写程序

istream_iterator<int> in_iter(cin);
istream_iterator<int> eof;
vector<int> vec(in_iter,eof);
这里用一对标记元素范围的迭代器构造vec对象。这些迭代器是istream_iterator对象。这就意味着这段范围的元素是通过读取所关联的流来获得的。这个构造函数效果是读cin,直到到达文件结束或输入的不是int型数值为止



3、ostream_iterator对象和ostream_iterator对象的使用
可使用ostream_iterator对象将一个值序列写入流中,其操作的过程与使用迭代器将一组值逐个赋给容器中的元素相同。

ostream_iterator<string> out_iter(cout,"\n");
istream_iterator<string> in_iter(cin),eof;
while(in_iter!=eof)
    *out_iter++=*in_iter++;
首先定义一个ostream_iterator对象,用于将string类型的数据写到cout中,每个string对象后跟一个换行符。定义两个istream_iterator对象,用于从cin中读取string对象。while循环类似前一例子。但是这一次不是将读取的数据存储在vector对象中,而是将读取的数据赋给out_iter,从而输出到cout上。



4、在类类型上使用istream_iterator提供了输入操作符(>>)任何类型可以创建istream_iterator对象。如下使用istream_iterator对象读取一系列的Sales_item对象并求和

istream_iterator<Sales_item> item_iter(cin),eof;
Sales_item sum;
sum=*item_iter++;
while(item_iter!=eof){
    if(item_iter->same_isbn(sum))
       sum=sum+*item_iter;
    else{
       cout<<sum<<endl;
       sum=*item_iter;
    }
    ++item_iter;
}
cout<<sum<<endl;


该程序将迭代器item_iter与cin绑在一起,意味迭代器将读取Sales_item类型的对象。然后读入第一个记录赋给sum:  sum=*item_iter++;

这个语句使用解引用操作符获取标准输入的第一个记录,并将这个值赋给sum。然后给迭代器加1,使流从标准输入中读取下一个记录。

   while循环反复执行直到cin的结束位置为止。在while循环中将刚读入记录的isbn与sum的isbn比较。while中的第一个语句使用了箭头操作符对istream迭代器进行解引用,获得最近读入的对象。然后在该对象和sum对象上调用same_isbn成员。。如果isbn值相同,则增加总和sum。否则输出sum的当前值,并将它重设为最近读取对象的副本。循环的最后一步是给迭代器加1,在本例中将导致从标准输入读入一个Sales_item对象。循环持续直到遇到错误或结束位置为止。在结束程序之前,记信输出从输入中读入最后一个ISBN所关联的值。。。



5、流迭代器的限制
不可能从ostream_iterator对象读入,也不可能写到istream_iterator对象中。。
一旦给ostream_iterator对象赋了一个值,写入就提交了,赋值后,没有办法再改变这个值。此外

ostream_iterator对象中每个不同的值都只能正好输出一次。
ostream_iterator没有->操作符



6、与算法一起使用流迭代器
istream_iterator<int> cin_it(cin);
istream_iterator<int> end_of_stream;
vector<int> vec(cin_it,end_of_stream);
sort(vec.begin(),vec.end());
ostream_iterator<int> output(cout," ");
unique_copy(vec.begin(),vec.end(),output);
如果程序输入是:
23 109 45 89 6 34 12 90 34 23 56 23 8 89 23
输出则是:
6 8 12 23 34 45 56 89 90 109

程序用一对迭代器input和end_of_stream创建了vec对象。这个初始化的效果是读取cin直到文件结束或出现错误为止。读取的值保存在vec中。读取输入和初始化vec后,调用sort对输入的数排序。

sort调用完成后,重复输入的数就会相邻存储。程序再使用unique_copy算法,这是unique的复制版本。该算法将输入范围中不重复的值,复制到目标迭代器。该调用将输出迭代器用作目标。其效果是将vec中不重复的值复制给cout每个复制的值后输出一空格。。



反向迭代器
是一种反向遍历容器的迭代器,也就是从最后一个元素到第一个元素遍历容器。反向迭代器将自增(自减)的含义反过来了。对于反向迭代器++运算访问前一个元素,而--运算则访问下一个元素。
所有容器都定义了begin和end成员。分别返回指向容器首元素和尾元素下一位置迭代器。容器还定义了rbegin和rend成员。分别返回指向容器尾元素和首元素前一位置的反向迭代器。
假设有一个vector容器对象,存储0----9这10个升序排列的数字。。
vector<int> vec;
for(vector<int>::size_type i=0;i!=10;++i)
    vec.push_pack(i);
下面的for循环将以逆序输出这些元素
vector<int>::reverse_iterator r_iter;
for(r_iter=vec.rbegin();r_iter!=vec.rend();++r_iter)
    cout<<*r_iter<<endl;
为了降序排列vector只需向sort一对反向迭代器
sort(vec.begin(),vec.end());
sort(vec.rbegin(),vec.rend());


1、反向迭代器需要使用自减操作符。。


2、反向迭代器与其他迭代器之间的关系。
有一名为line的string对象。存储以逗号分隔的单词列表。我们希望输出line中的第一个单词。使用find可实现
string::igerator comma=find(line.begin(),line.end(),',');
cout<<string(line.begin(),comma)<<endl;
如果line中有一个逗号,则comma指向这个逗号,否则comma的值为line.end()。在输出string对象从line.begin()到comma的内容时,从头开始输出字符直到遇到逗号为止。如果string对象中没有逗号则输出整个string字符串。。
如果要输出列表最后一个单词,可使用反向迭代器
string::reverse_iterator rcomma=find(line.rbegin(),line.rend(),',');
因为此时传递的是rbegin()和rend()这个函数用从line的最后一个字符开始往回搜索当find完成时,如果列表中有逗号,那么rcomma指向其最后一个逗号,即指向反向搜索找到的第一个逗号,如果没有逗号,则rcomma的值为line.rend()。在尝试输出所找到的单词时,
cout<<string(line.rbegin(),rcomma)<<endl;
如果输入是:  FIRST,MIDDLE,LAST  则将输出TSAL


使用反向迭代器时,以逆序从后向前处理string对象。为了得到正确输出,必须将反向迭代器line.rbegin()和rcomma转换为从前向后移动的普通迭代器。其实没必要转换line.rbegin(),因为我们知道转换的结果必定是line.end()。只需调用所有反向迭代器类型都提供的成员函数base转换rcomma即可
cout<<string(rcomma.base(),line.end())<<endl;

const迭代器
find_first_of(it,roster1.end(),roster2.begin(),roster2.end())
该函数调用的输入范围由it和调用roster1.end()返回的迭代器指定。算法要求用于指定范围的两个迭代器必须具有完全一样的类型。roster1.end()返回的迭代器依赖于roster1的类型。如果该容器是const对象,则返回的迭代器是const_iterator类型。否则就是普通的iterator类型。在这个程序中roster1不是const对象,因而end返回的只是一个普通的迭代器。如果我们将it定义为const_iterator那么find_first_of的调用将无法编译。用来指定范围的两个迭代器的类型不相同,it是const_iterator类型的对象。而rostser1.end()返回则是一个iterator对象。。

迭代器种类
输入迭代器  读,不能写:只支持自增运算

可用于读取容器中的元素,但是不保证能支持容器的写入操作。输入迭代器必须至少提供下列支持
1、相等和不等操作符(==,!=)比较两个迭代器
2、前置和后置的自增运算(++)使迭代器向前递进指向下一个元素
3、用于读取元素的解引用操作符(*),此操作符只能出现在赋值运算的右操作数上
4、箭头操作符(->)这是(*it).member的同义语,也就是说,对迭代器进行解引用来获取所关联的对象的成员
输入迭代器只能顺序使用:一旦输入迭代器自增了,就无法再用它检查之前的元素。要求在这个层次上提供支持的泛型算法包括find和accumulate。标准库istream_iterator类型是输入迭代器


输出迭代器  写,不能读:只支持自增运算

可视为与输入迭代器功能互补的迭代器。输出迭代器可用于向容器写入元素,但是不保证能支持读取容器内容
1、前置和后置的自增运算(++)使迭代器向前递进指向下一个元素。。
2、解引用操作符(*)。此操作符只能出现在赋值运算的左操作数上。给解引用的输出迭代器赋值。将对该迭代器所指向元素做写入操作。
输出迭代器可以要求每个迭代器的值必须正好写入一次。使用输出迭代器时,对于指定的迭代器值应该使用一次*运算,而且只能用一次。输出迭代器一般用作算法的第三个实参,标记起始写入的位置。如: copy算法使用一个输出迭代器作为它的第三个实参,将输入范围内的元素复制到输出迭代器指定的目标位置。标准ostream_iterator类型是输出迭代器。。

前向迭代器  读和写:只支持自增运算

用于读写指定的容器。这个类迭代器只会以一个方向遍历序列。前向迭代器支持输入迭代器和输出迭代器提供的所有操作,除此之外,还支持对同一个元素的多次读写。可复制前向迭代器和输出迭代器提供的所有操作,除此之外还支持对同一个元素的多次读写。可复制前向迭代器来记录序列中的一个位置,以便将来返回此处。需要前向迭代器的泛型算法包括replace。


双向迭代器  读和写:支持自增和自减运算

从两个方向读定容器。除了提供前向迭代器的全部操作之外,双向迭代器还提供前置和后置的自减运算(--)。需要使用双向迭代器泛型算法包括reverse。所有标准库容器提供的迭代器都至少达到双向迭代器的要求

随机访问迭代器  读和写:支持完整的迭代器算术运算

提供在常量时间内访问容器任意位置的功能。这种迭代器除了支持双向迭代器所有功能外。还支持下面的操作:
1、关系操作< <= > >=。。比较两个迭代器相对位置
2、迭代器与整型数值n之间的加法和减法操作符+ += - -= 结果是迭代器在容器中向前(向后)n个元素
3、两个迭代器之间的减法操作符(-),得到两个迭代器间的距离。
4、下标操作符iter[n]这是*(iter+n)的同义词
需要随机访问迭代器的泛型算法包括sort算法.vector  deque  string迭代器是随机访问迭代器

map set list类型提供双向迭代器,而string vector deque容器上定义的迭代器都是随机访问迭代器,用作访问内置数组元素的指针也是随机访问迭代器。istream_iterator是输入迭代器,而ostream_iterator则是输出迭代器。。
尽管map set类型提供双向迭代器。但关联容器只能使用算法的一个子集,因为关联窗口的键是const对象。因此,关联容器不能使用任何写序列元素算法。只能使用与关联容器绑在一起的迭代器来提供用于读操作的实参。在处理算法时将关联容器上的迭代器视为支持自减运算的输入迭代器。而不是完整的双向迭代器。
C++标准为所有泛型和算术算法的每一个迭代器形参指定了范围最小的迭代器种类。如find(以只读方式单步遍历容器)至少需要一个输入迭代器。replace函数至少需要一对前向迭代器。replace_copy函数的头两个迭代器必须至少是前向迭代器,第三个参数代表输出目标。必须至少是输出迭代器。对于每一个形参。迭代器必须保证最低功能。将支持更少功能的迭代器传递给函数是错误。而传递更强功能的迭代器则是没问题。。


泛型算法的结构
任何其他的算法分类都含有一组形参规范。理解这些形参规范有利于学习新的算法
alg(beg,end,other parms);
alg(beg,end,dest,other parms);
alg(beg,end,beg2,other parms);
alg(beg,end,beg2,end2,other parms);
其中alg是算法的名字,beg和end指定算法操作的元素范围。我们通常将该范围称为算法的“输入范围”.dest beg2 end2它们都是迭代器形参。
1、带有单个目标迭代器的算法 dest形参是一个迭代器,用于指定存储输出数据的目标对象。算法假定无论需要写入多少个元素都是安全的。调用这些算法时,必须确保输容器有足够大的容量存储输出数据。这正是通常要使用插入迭代器或者ostream_iterator来调用这些算法的原因。如果dest是容器上的迭代器,则算法将输出内容写到容器中已存在的元素上。更普遍的用法是将dest与某个插入迭代器或者ostream_iterator绑定在一起。插入迭代器在窗口中添加元素以确保容器有足够的空间存储输出。ostream_iterator则实现流的功能。无需考虑所写的元素个数..
2、带有第二个输入序列的算法
有一此算法带有一个beg2迭代器形参。或者同时带有beg2和end2迭代器形参,来指定它的第二个输入范围。这类算法通常将联合两个输入范围的元素来完成计算功能。算法同时使用beg2和end2时,这些迭代器用于标记完整的第二个范围。也就是说,此时,算法完整地指定了两个范围:beg和end标记第一个输入范围。而beg2和end2则标记第二个输入范围
带有beg2而不带end2的算法将beg2视为第二个输入范围的首元素,但没有指定该范围的最后一个元素这些算法假定以beg2开始的范围至少与beg和end指定的范围一样大。与写入dest的算法一样。只带有beg2的算法也假定以beg2开始的序列与beg和end标记的序列一样大


算法的命名规范
1、区别带有一个值或一个谓词函数参数的算法版本。
重新对容器元素排序的算法要使用<操作符。这些算法的第二个重载版本带有一个额外的形参,表示用于元素排序的不同运算
sort(beg,end);
sort(beg,end,pred);
检查指定值的算法默认使用==操作符。系统为这类算法提供另外命名版本。带有谓词函数形参。带有谓词形参的算法其名字后缀上_if
find(beg,end);
find_if(beg,end,pred);
find算法查找一个指定的值。而find_if算法则用于查找一个使谓词函数pred返回非零值的元素。
2、区别是否实现复制的算法版本
无论算法是否检查它的元素值。都可能重新排列输入范围内的元素。在默认情况下,这些算法将重新排列的元素写回其输入范围。标准库也为这些算法提供另外命名的版本。将元素写到指定的输出目标。此版本算法在名字中添加_copy后缀
reverse(beg,end);
reverse_copy(beg,end,dest);
reverse函数功能 就如它的名字,将输入序列的元素反向重新排列。其中,第一个函数版本将自己的输入序列中元素反向重排。而第二个版本则复制输入序列的元素。并将它们以逆序存储到位dest开始序列中。。
上述两个算法都在输入范围内寻找指定元素的第一个实例。

容器特有的算法

list容器特有操作
lst.merge(lst2)
lst.merge(lst2,comp)
将lst2的元素合并到lst中,这两个list容器对象都必须排序。lst2中的元素将被删除。合并后。lst2为空。返回void类型。第一个版本使用<操作符,而第二个版本使用comp指定的比较运算
lst.remove(val)
lst.remove_if(unarypred)
调用lst.erase删除所有等于指定值或指定的谓词函数返回非零值的元素。返回void类型
lst.reverse()  反向排列lst中的元素
lst.sort()  对lst中元素排序
lst.splice(iter,lst2)
lst.splice(iter,lst2,iter2)
lst.splice(iter,beg,end)
将lst2的元素移到lst中迭代器iter指向的元素前面。在lst2中删除移出的元素。第一个版本将lst2的所有元素移到lst中;合并后,lst2为空。lst和lst2不能是同一个list对象。第二个版本只移动iter2所指向的元素。这个元素必须是lst2中的元素。在这种情况中。lst和lst2可以是同一个list对象。也就是说可在一个list对象中使用splice运算移动一个元素。第三个版本移动迭代器beg和end标记的范围内的元素。beg和end照例必须指定一个有效的范围。这两个迭代器可标记任意list对象内的范围包括lst。当它们指定lst的一段范围时,如果iter也指向这个范围内的一个元素。则该运算未定义
lst.uniqu()
lst.uniqu(binarypred)  调用erase删除同一个值的连续副本。第一个版本使用==操作符判断元素是否相等。第 二个版本则使用指定的谓词函数实现判断

对于list对象应优先使用list容器特有成员版本,而不泛型算法 
list特有算法与其泛型算法版本之间有两个至关重要的差别。其中一个差别是remove和unique的list版本修改了其关联容器真正删除了指定的元素。如list::unique将list中第二个和后续重复的元素删除出该容器。
另一个关别就是list容器提供的merge和splice运算会破坏它们的实参。使用merge的泛型算法版本时,合并的序列将写入目标迭代器指向的对象,而它的两个输入序列保持不变。但是使用list容器的merge成员函数时则会破坏它的实参list对象。当实参对象的元素合并到调用merge函数的list对象时。实参对象的元素被移出并删除...

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值