C++ Primer 学习笔记_42_STL实践与分析(16)(一)

2014-11-24 12:10:33 · 作者: · 浏览: 0

STL实践与分析

--再谈迭代器【上】


引言:

另外三种迭代器类型:

1)插入迭代器:这类迭代器与容器绑定在一起,实现在容器中插入元素的功能。

2)iostream迭代器:这类迭代器可以与输入与输出流绑定在一起,用于迭代遍历所关联的IO流。

3)反向迭代器:这类迭代器实现向后遍历,而不是向前遍历,所有的容器都定义了自己的reverse_iterator类型,由rbegin和rend成员函数返回。

上述迭代器都在iterator头文件中定义。

一、插入迭代器

前面曾经提到的back_inserter函数是一种插入器,插入器适宜用迭代器适配器,其带有一个容器参数,并生成一个迭代器,用于在指定容器中插入元素。通过插入迭代器赋值时,迭代器将会插入一个新的元素。

C++提供了三种插入迭代器,其差别在于插入元素的位置不同:

1)back_inserter:创建使用push_back实现插入的迭代器。

2)front_inserter:使用push_front实现插入。

3)inserter:使用insert实现插入操作。出了所关联的容器外,inserter还带有第二个实参:指向插入起始位置的迭代器。

1、front_inserter需要使用push_front

front_inserter的操作类似于back_inserter:该函数创建一个迭代器,调用它所关联的基础容器的push_front成员函数代替赋值操作。

    deque
  
    iDeq;
    front_inserter(iDeq) = 1;   //OK

    vector
   
     iVec; front_inserter(iVec) = 1; //Error back_inserter(iVec) = 1; //OK 
   
  

只有当容器提供 push_front操作时,才能使用front_inserter。在vector或其他没有push_front运算的容器上使用front_inserter,将产生错误。

2、inserter将产生在指定位置实现插入的迭代器

inserter适配器提供更普通的插入形式。这种适配器带有两个实参:所关联的容器和指示起始插入位置的迭代器。

    list
  
   ::iterator it = find(iList.begin(),iList.end(),42);
    /*
    *在创建 inserter 时,应指明新元素在何处插入。
    *inserter 函数总是在它的迭代器实参所标明的位置前面插入新元素。
    */
    replace_copy(iVec.begin(),iVec.end(),inserter(iList,it),0,100);

  

3、inserter+容器的begin组合与 front_inserter的区别:

在使用front_inserter时,元素始终在容器的第一个元素前面插入。而使用inserter时,元素则在指定位置前面插入。

    //理解下面输出的区别
    list
  
    ilst,ilst1,ilst2;

    for (list
   
    ::size_type index = 0; index != 4; ++index) { ilst.push_front(index); } copy(ilst.begin(),ilst.end(),front_inserter(ilst1)); copy(ilst.begin(),ilst.end(),inserter(ilst2,ilst2.begin())); cout << "iList1: " << endl; for (list
    
     ::iterator iter = ilst1.begin(); iter != ilst1.end(); ++iter) { cout << *iter << '\t'; } cout << endl << "iList2: " << endl; for (list
     
      ::iterator iter = ilst2.begin(); iter != ilst2.end(); ++iter) { cout << *iter << '\t'; } cout << endl; 
     
    
   
  

【小心地雷:】

front_inserter的使用将导致元素以相反的次序出现在目标对象中!

//P349 习题11.14
void printList(const list
  
    &iList)
{
    for (list
   
    ::const_iterator iter = iList.begin();iter != iList.end(); ++iter) { cout << *iter << '\t'; } cout << endl; } int main() { list
    
      iList; list
     
       iList1,iList2,iList3; for (list
      
       ::size_type i = 0;i != 10; ++i) { iList.push_back(i); } cout << "iList: " << endl; printList(iList); replace_copy(iList.begin(),iList.end(),front_inserter(iList1),0,100); cout << "iList1: " << endl; printList(iList1); replace_copy(iList.begin(),iList.end(),inserter(iList2,iList2.begin()),0,100); cout << "iList2:" << endl; printList(iList2); replace_copy(iList.begin(),iList.end(),back_inserter(iList3),0,100); cout << "iList3:" << endl; printList(iList3); } 
      
     
    
   
  

二、iostream迭代器

虽然iostream类型不是容器,但是标准库同样提供了iostream对象上使用的迭代器:istream_iterator用于读取输入流,而ostream_iterator用于写输出流。这些迭代器将它们所对应的流视为特定类型的元素序列。使用流迭代器时,可以用泛型算法从流对象中读取数据或写数据到流对象中。

iostream迭代器的构造函数

istream_iterator in(strm);

创建从输入流strm中读取T类型对象的istream_iterator对象

istream_iterator in;

istream_iterator对象的超出末端迭代器

ostream_iterator in(strm);

创建将T类型的对象写入到输出流strmostream_iterator对象

ostream_iterator in(strm,delim);

创建将T类型的对象写入到输出流strmostream_iterator对象,再写入过程中使用delim作为元素的分隔符。delimit是以空字符结束的字符数组。

流迭代器只定义了最基本的迭代器操作:自增、解引用和赋值。此外,可比较两个istream迭代器是否相等(或不等)。ostream迭代器则不提供比较运算

istream_iterator的操作

it1== it2

it1!= it2

比较两个istream_iterator对象是否相等/不等。迭代器必须读取的是相同的类型。如果两个迭代器都是end值,则它们相等。对于两个都不指向流结束符位置的迭代器,如果它们使用同一个输入流构造,则它们也相等。

*it

返回从流中读取的值

it-> mem

是(*it).mem的同义词,返回从流中读取的对象的mem成员

++it

it++

通过使用元素类型提供的>>操作符从输入流中获取下一个元素值,使迭代器向前移动。通常,前缀版本使迭代器再流中向前移动,并返回对加1后的迭代器的引用。而后缀版本使迭代器在流中向前移动后,返回原值


1、流迭代器的定义

流迭代器都是类模板:任何已定义输入操作符(>>操作符)的类型都可以定义stream_iterator。类似地,任何已定义输出操作符(<<操作符)的类型也可定义ostream_iterator。

在创建流迭代器时,必须指定迭代器所读写的对象类型:

    istream_iterator
  
    cin_it(cin);
    istream_iterator
   
     end_of_stream; ofstream outfile; ostream_iterator
    
      cout_it(outfile," ");