您的位置:首页 > 编程语言 > C语言/C++

c++迭代器总结

2015-10-11 15:35 239 查看
迭代器定义:迭代器是一种检查容器内元素并遍历元素的数据类型。对于数组而言,可以通过下标操作检查容器内元素并遍历元素,但是对于容器来说,并不是所有的容器都能够通过下标操作元素,而迭代器对所有的容器都适用,所以现在c++程序更倾向于用迭代器而不是下标操作访问元素,即是某些容器如vector支持下标操作。

1、所有的标准库容器都定义了相应的迭代器类型,对于不同的容器迭代器支持的操作又存在异同。

a、普适的迭代器操作

(1)begin和end操作:每一个容器都定义了一对命名为begin和end的函数,用于返回迭代器。由begin返回的迭代器指向的是容器的第一个元素(在容器有元素的前提下),由end返回的迭代器指向的是容器末端元素的下一个,即超出末端迭代器。在容器为空的情况下,容器调用begin和end函数返回的迭代器相同。

例:vector<
int
>::iterator iter=ivec.begin();//vector容器不是空时,iter=ivec[0];

vector<
int
>::iterator iter=ivec.end();//由end返回的迭代器并不指向vector容器的任何一个元素,相反它只是一个哨兵的作用,表示我们已经处理完vector容器内元素。

(2)容器迭代器的自增和解引用操作:迭代器类型可使用解引用操作来访问迭代器指向的元素:*iter=0;解引用操作符返回迭代器当前所指向的元素。

for(vector<
int
>::iterator iter=ivec.begin();iter!=ivec.end();++iter){*iter=0;}

//上面那段代码便利用解引用操作将vector中的容器的每一个元素都设置为0,并且用到了迭代器自增操作(++iter);每次循环迭代器加1,这样便可以遍历整个容器。

下面列出迭代器为所有标准库容器所提供的运算:

<
1
>*iter
//返回迭代器iter所指向的元素的引用

<
2
>iter->men
//对iter进行解引用,获取指定元素中名为men的成员

<
3
>++iter
//给迭代器iter加1,使其指向容器里的下一个元素

<
4
>iter++
//给迭代器iter加1,使其指向容器里的下一个元素

<
5
>–iter
//给迭代器iter减1,使其指向容器里的上一个元素

<
6
>iter–
//给迭代器iter减1,使其指向容器里的上一个元素

<
7
>iter1==iter2
//比较两个迭代器是否相等

<
8
>iter1!=iter2
//比较两个迭代器是否相等

b:部分容器使用的迭代器操作(c++容器中定义的只有vector和deque容器可以提供下面的迭代器操作:迭代器算术运算以及使用除了==和!=之外的关系操作符来比较两个迭代器)。下面列举vector和deque类型迭代器支持的操作:

<
1
>iter+n/iter-n
//在迭代器上面加(减)整数值n,将产生指向迭代器中前面(后面)第n个元素的迭代器,新计算出来的迭代器必须指向容器中的元素或是超出容器末端的下一个位置

<
2
>iter1+=iter2/iter1-=iter2
//这是迭代器加减法的复合赋值运算,将iter1加上或是减去iter2的运算结果赋给iter1

<
3
>比较符:>、<、>=、<=
//迭代器的关系操作符

为什么这些迭代器的操作只适用于vector和deque容器,是和容器本身的属性是有一定关系的,因为只有这两种容器为元素提供快速、随机的访问。他们确保可根据元素位置直接有效的访问指定的容器元素。这两种容器都支持通过元素位置实现随机访问,因此他们的迭代器可以有效的实现算术和关系运算。

错误案例: list<
int
> ilist(vec.begin(),ivec.end()); ilist.begin()+ilist.size()/2;

//list容器并不支持算术运算和关系运算,所以不能使用在list容器上。

2、const_iterator和const迭代器

(1)const_itetator类型

for(vector<
string
>::const_iterator iter=ivec.begin();iter!=ivec.end();++iter)

{cout<< *iter<< endl;}//这段代码是正确的,const_iterator类型只能够用于读取容器内的元素但是不能够修改容器中元素的值。

for(vector<
string
>::const_iterator iter=ivec.begin();iter!=ivec.end();++iter)

{*iter=0;}//这段代码是错误的,因为它修改了容器中元素的值了

(2)const迭代器(即const的itetator对象)

vector<
int
> nums(10);

const vector<
int
>::iterator cit=nums.begin();

*cit=10;//这个操作是正确的,可以const迭代器中容器的值是可以修改赋值的。

++cit;//这个操作是错误的,因为迭代器是const类型,所以不能修改迭代器自身。

从上面便可以看出const_iterator和const迭代器的区别了,const_iterator中迭代器自身是可以进行修改和自增操作的,但是骑修饰的容器中的元素是不能修改的,既可理解成容器中的元素是const类型的;但是const迭代器表示的是迭代器自身是const类型,所以迭代器不能进行自增等操作,但是容器中的元素是可以进行修改和赋值操作的。所以一般情况下const迭代器不会使用,因为不能遍历容器,只能够单一的取出容器中的某一个值。

3、其实迭代器并不依赖于特定的容器,下面介绍另外三种迭代器,这三个迭代器都在iterator头文件中。

(1)插入迭代器(insert iterator):这类迭代器与容器是绑定在一起的,实现了在容器中插入元素功能。其中提供下面三种差入方式:

<
1
>back_inserter,
创建使用push_back实现插入的迭代器;

<
2
>front_inserter,
使用push_back实现插入;

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

下面通过代码说明上面三个插入使用方法:

<
1
>
vector<
int
> vec;

fill_n(back_inserter(vec),10,0);//此段代码的效果相当在vec上面调用push_back,在vec末尾添加了十个值为0 的元素

<
2
>
front_inserter的操作类似于back_inserter,只是front_inserter是在容器的开头插入元素,相当于调用push_front操作(因此vector容器便不能够使用这个函数)

<
3
>
list<
int
>::iterator it=find(ilst.begin(),ilst.end(),42);

replace_copy(ivec_begin(),ivec.end(),inserter(ilst,it),100,0);//这段代码的效果就是先在ilst容器中找到元素42的迭代器,然后调用replace_copy函数,将ivec容器中元素为100的全部替换形成0,再在ilst容器的it前面插入替换后的ivec容器。

&注意: 我们认为有可能可以使用inserter和begin迭代器可以模拟front_inserter的效果,其实不然,下面举例说明:

list<
int
> ilst,ilst2,ilst3;

for(list<
int
>::size_type i=0;i!=4;++i){ilst.push_back();}

copy(ilst.begin(),ilst.end(),front_inserter(ilst2));//front_inserter操作

copy(ilst.begin(),ilst.end(),inserter(ilst3,ilst3.begin()));//inserter操作

实际上第一个front_inserter作用的结果得到的容器中元素顺序是3210,而通过inserter操作容器中元素顺序是0123。因为front_inserter是总在首元素的前面插入的,而inserter确实在固定位置处一直插入的。

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

<
1
>
istream_iterator对象上面的操作(下面介绍两种类似且作用效果相同的读取流中元素的方法):

a、 istream_iterator<
int
> in_iter(cin);//这向的是流cin中的第一个元素

istream_iterator<
int
> eof;//指向流中最后一个元素

while(in_iter!=eof){vec.push_back(*in_iter++);}//将元素读到了vec容器中了

b、 istream_iterator<
int
> in_iter(cin);

istream_iterator<
int
> eof;

vector<
int
> vec(in_iter,eof);//实现和上面同样的效果

<
2
>
在类类型上使用istream_iterator(提供输入操作符的任何类型都可以使用创建istream_iterator对象)举例代码如下:

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;

<
3
>
与算法一起使用的流迭代器(算法是基于迭代器实现的,一些泛型算法可以用到流迭代器进行一起操作)代码如下:

istream_iterator<
int
> cin_it(cin);

istream_iterator<
int
> end_of_stream;

vector<
int
> ivec(cin_ct,end_of_stream);

sort(vec.begin(),ivec,end());

ostream_iterator<
int
> output(cout,” “);

unique_copy(ivec.begin(),ivec.end(),output);

&注意: 关于使用插入迭代器和iostream迭代器的另外的重要原因:对于一些泛型算法,特别是写容器元素算法如:fill和fill_n,这些算法这使用的时候都必须对容器已经存在的元素才能够进行写入操作,所以有时就容易出现都不检查目标容器的大小是否足以储存写入的元素,这样并易出现一些错误。对于这些算法,我们必须保证容器中有足够大的空间存储输入的数据,这正是为什么使用插入迭代器和iostream迭代器的原因所在,因为这些迭代器可以在容器中自动生成迭代器来存储多的元素。

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

反向迭代器可以实现将容器元素输出序列的顺序,简单代码如下:

vector<
int
>::reverse_iterator r_iter;

for(r_iter=vec.rbegin();r_iter!=vec.rend();++r_iter){cout<< *r_iter<< endl;}

4、迭代器失效,一般对于容器迭代器来说,当一些操作引起容器内内存充分配时,便会引起迭代器失效,关于插入和删除等操作一般易引起迭代器失效的总结如下:

(1)insert操作 插入点之后所有迭代器失效,但如果引起内存重分配则所有迭代器失效

(2)erase操作 删除点之后所有迭代器失效

(3)push_back操作 一般不引起迭代器失效,但如果引发内存重分配则所有迭代器失效

(4)vector的reserve操作 会使得迭代器全部失效(引起了内存重分配)

(5)swap操作 不会使得迭代器失效
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: