C++学习之迭代器

来源:互联网 发布:三菱plc编程实例精解 编辑:程序博客网 时间:2024/06/14 15:22

C++标准库中的3个重要概念就是容器,迭代器,算法,标准库中的常用容器有vector,list,deque,map,set,multimap,multiset(C++11中新增了array,forward_list,unordered_map,unordered_set,unordered_multimap,unordered_multiset),这些容器大家都经常用到,相对比较熟悉。但是使用C++,就必须得熟悉其提供给我们的100多个泛型算法(参见C++学习之标准库泛型算法_STL算法),这样我们就可以避免重复造轮子。泛型算法不是调用容器已有的操作实现,而是借助于迭代器来实现,所以调用泛型算法的时候,我们需要传递迭代器参数来指明输入范围和输出范围,所以在学习泛型算法之前,必须先了解迭代器的概念,类型等。

下面是我在看了C++primer第11章泛型算法后自己的理解:

一、什么是迭代器?

我的理解是迭代器提供了一种遍历容器内元素的方法,比如遍历数组可以通过指针实现,指针就可以认为是一种迭代器,可以参见C++ Primer的p84 。

我认为迭代器没有责任去检测越界,比如当某个迭代器位于超出末端下一位置,如果再对它进行自增运算,那么就会出现运行时错误:“iterator not incrementable"。

二、迭代器种类

1.从迭代器的类型上对迭代器分类

(1)普通迭代器:就是我们经常使用的 容器::iterator,比如std::vector<int>::iterator,一般都支持++、--操作,其他算术操作看具体的容器类型;

(2)反向迭代器:这一种迭代器也是经常用到的,比如std::list<int>::reverse_iterator,一般都支持++、--操作,其他算术操作看具体的容器类型;

          反向迭代器的通过使用普通迭代器的自减操作实现的,所以从一个支持--同时也支持++的迭代器就可以定义反向迭代器

         *上面两种类型的迭代器都有相应的const迭代器,const迭代器不能修改其指向的元素,比如std::list<int>::const_iterator,std::list<int>::const_reverse_iterator,const迭          代器类似于const int* p。

(3)流迭代器:输入输出流不是容器,但是标准库将它看作了容器,流迭代器只支持向前遍历(++)这是流的特点决定的,因此流迭代器不能创建反向迭代器。流迭代器分为了istream_iterator和ostream_iterator,分别用于遍历输入、输出流,并且我们只能从istream_iterator读入输入流的内容,通过ostream_iterator写出到输出流。

        istream_iterator提供的操作

               it1==it2 比较两个迭代器是否相同。

               it1!=it2  如果两个都指向end,那么it1==it2;如果均不指向end,且由同一个输入流构造,那么也相等。

                             比较运算符必须是 读取相同类型的两个流迭代器

               *it  返回从流中读取的值,作为右值使用

               it->v  或 (*it).v 返回读取对象的成员v

               ++it 

               it++

         ostream_iterator 只提供*it (作为左值使用),++it ,it ++,不提供比较和成员选择操作。

         流迭代器的构造函数

         istream_iterator<T> in(stream)    创建从输入流stream读入T类型对象的 istream_iterator对象

         istream_iterator<T> in                   istream_iterator对象的超出末端迭代器

         ostream_iterator<T> out(stream)    创建将T类型对象写出到输出流stream的ostream_iterator对象,可以指名输出时的分隔符,如下

         ostream_iterator<T> out(stream,delim)  

         *ostream_iterator 不提供比较函数,所以就没必要定义其对应的超出末端的迭代器了

         任何定义了输入操作符(>>)的类型都能定义都可以定义 istream_iterator,同时任何定义了输出操作符(<<)的类型都能定义都可以定义 ostream_iterator

         下面是流迭代器的例子        

//将input.txt 内容拷贝到output.txt,以换行符分隔输出ifstream fileIn("input.txt");istream_iterator<string> iit(fileIn);istream_iterator<string> eof;ofstream fileOut("output.txt");ostream_iterator<string>oit(fileOut,"\n");copy(iit,eof,oit);fileOut.clear();fileOut.close();fileIn.clear();fileIn.close();

(4)插入迭代器:插入迭代器实际是迭代器适配器,它又分为了首插入迭代器、尾插入迭代器、指定位置插入迭代器,即front_inserter,back_inserter,inserter.

          适配器的概念可以参见http://kingphp.blog.163.com/blog/static/200423244201272953254508/,这里插入适配器,带有一个容器形参,并生成一个在此容器上的一个迭代器,用于向容器中插入元素,首插入迭代器、尾插入迭代器、指定位置插入迭代器的位置分别是容器首部、超出末端第一个位置、指定位置,(C++STL插入的意思是在指定位置前添加元素),并且在多次使用某个插入迭代器的时候,其位置永远是容器首部、尾部、指定的位置。比如下面的代码:

#include<iostream>#include<iterator>#include<list>#include<algorithm>int main(int argc,char**argv){std::list<int> vInt1,vInt2;for(int i=0;i<5;++i){vInt1.push_back(i);vInt2.push_back(i+5);}//vInt1 0,1,2,3,4//vInt2 5,6,7,8,9//使用inserter vInt1 copy到 vInt2的7的前面//结果 5 6 0 1 2 3 4 7 8 9std::copy(vInt1.begin(),vInt1.end(),std::inserter(vInt2,std::find(vInt2.begin(),vInt2.end(),7)));for(std::list<int>::iterator it=vInt2.begin();it!=vInt2.end();++it)std::cout<<*it<<" ";std::cout<<std::endl;//使用front_inserter vInt1 copy到 vInt2 前面//结果 4 3 2 1 0 5 6 0 1 2 3 4 7 8 9std::copy(vInt1.begin(),vInt1.end(),std::front_inserter(vInt2));for(std::list<int>::iterator it=vInt2.begin();it!=vInt2.end();++it)std::cout<<*it<<" ";std::cout<<std::endl;return EXIT_SUCCESS;}

值得注意的是front_inserter,back_inserter,inserter分别调应其参数类型容器的push_front,push_back,insert操作,所以得要求容器具有相应的操作才行,比如不能在vector上构造front_inserter。

2.通过STL中泛型算法对迭代器参数类型的要求对迭代器分类

(1)输入迭代器  只读(一次),不写,支持自增 ,如istream_iterator

(2)输出迭代器  只写(一次),不读,支持自增,如ostream_iterator

(3)前向迭代器  支持同一元素的多次读写

(4)双向迭代器  从两个方向读写,如list<t>::iterator

(5)随机访问迭代器   在常量时间内读写任意位置, vector,deque,string可以提供,常用的指针也是。

这几种迭代器具有层次结构(具体层次结构请参见C++学习之深入理解迭代器),下层具有上层的功能,并且添加了添加一些额外的操作,如下图。


注意:所有标准库提供的迭代器都至少达到双向迭代器的要求;

           由于关联容器map,set的键是const类型,不能写入,所以将关联容器的迭代器视为支持自减运算的输入迭代器,而不是完整的双向迭代器;

           算法中用于标记范围的一对迭代器必须是同种类型。


0 0
原创粉丝点击