迭代器的本质和使用

时间:2024-04-06 16:05:59

迭代器:把标志控制的循环和计数控制的循环统一为一种控制,即迭代器控制,每一次迭代操作中对迭代器的修改就等价于修改标志或计数器。

容器迭代器:类似于数据库中的游标(cursor),屏蔽了底层存储空间的不连续性,在上层使容器元素维持一种“逻辑连续”的假象。工作逻辑如下:

迭代器的本质和使用

 

不可把迭代器与void*和“基类指针”混淆:指针代表真正的内存地址,即对象在内存中的存储位置;迭代器则代表元素在容器中的相对位置。

STL把迭代器分为5类,它们都是类模板,具有通用性。如下表:

迭代器的本质和使用

迭代器的本质和使用

迭代器能力大小:输入迭代器,输出迭代器 <  前进迭代器 <  双向迭代器 <  随机访问迭代器 

常用迭代器所属迭代器类别:

& Vector的迭代器为随机访问迭代器,因为它就是原始指针;

& list的迭代器是双向迭代器,因为list是双向链表;

& slist的迭代器是前进迭代器;

& deque的迭代器是随机访问迭代器;

& set/map的迭代器是双向迭代器;

......

迭代器使用建议:

1)尽量使用迭代器类型,而不是显示地使用指针。例如使用vector<int>::iterator,而不是int *,虽然他们等价。

2)只使用迭代器提供的标准操作,不要使用任何非标准操作,以避免STL版本更新的时候出现不兼容问题。

3)当不会改动容器中元素值的时候,使用const迭代器(const_iterator)。

迭代器失效的危险性:迭代器失效是指其指向容器中的某个或某些元素的存储发生了变化,使之成为无效迭代器,使用无效迭代器同时用无效指针一样危险。

解决迭代器失效问题有两种方式:1)在代用迭代器时重新获取迭代器;2)在修改容器前为其预留足够的空闲空间以避免存储空间重分配。

提示:顺序容器vector和string都可用reserve()和resize()来预留空间或调整它们的大小:reserve()用来保留(扩充)容量,它并不改变容器的有效元素个数;resize()则调整容器大小(size,有效元素个数),而且有时候会大容器的容量。当把这两个函数与assign()、insert()、push_back()、replace()及泛型算法搭配起来使用的时候,需要小心。

解决无效迭代器示例如下:

//迭代器失效程序

#include<iostream>

#include<vector>

using namespace std;

void main(){

    vector<int> ages;  //未预留空间

    ages.push_back(2);  //引起内存重分配

    vector<int>::const_iterator p = ages.begin();

    for(int i = 0; i<10; i++){

        ages.push_back(5);  //引起若干次内存重分配

    }

    cout<<"The first age:"<<*p<<endl; //p已经失效,危险访问

}

//解决方案1,重新获取迭代器

void main(){

    //...

    vector<int>::const_iterator p = ages.begin();

    for(int i = 0;i<10; i++){

        ages.push_back(5);  //引起若干次内存重分配

    }

    p = ages.begin();  //重新获取迭代器

    cout<<"The first age:"<<*p<<endl;  //OK

}

转自:https://blog.csdn.net/open_gis/article/details/12058671?utm_source=copy