STL迭代器概述
一个迭代器是一个对象,可以遍历(迭代)的容器类,而无需知道该容器是如何实现的。对于许多类(特别是列表和关联类),迭代器是访问这些类的元素的主要方式。
迭代器最好可视化为指向容器中给定元素的指针,并带有一组重载运算符以提供一组明确定义的函数:
Operator* 取消引用迭代器并且返回迭代器当前指向的元素。
Operator ++将迭代器移动到容器中的下一个元素。大多数迭代器也提供Operator–移动到前一个元素。
Operator==和Operator!= 基本比较运算符,用于确定两个迭代器是否指向同一个元素。要比较两个迭代器指向的值,首先取消引用迭代器,然后使用比较运算符。
Operator = - 将迭代器分配给新位置(通常是容器元素的开头或结尾)。要指定迭代器指向的元素的值,首先取消引用迭代器,然后使用assign运算符。
每个容器包括四个用于Operator =的基本成员函数:
begin()返回一个迭代器,表示容器中元素的开头。
end()返回一个迭代器,表示刚好超出元素末尾的元素。
cbegin()返回一个const(只读)迭代器,表示容器中元素的开头。
cend()返回一个const(只读)迭代器,表示元素刚刚结束的元素。
end()并不指向列表中的最后一个元素似乎很奇怪,但这主要是为了使循环变得容易:迭代元素可以继续,直到迭代器到达end(),然后你知道你了需要重做。
最后,所有容器都提供(至少)两种类型的迭代器:
container :: iterator提供了一个读/写迭代器
container :: const_iterator提供了一个只读迭代器
让我们看一下使用迭代器的一些例子。
通过向量迭代
#include <iostream>
#include <vector>
int main()
{
using namespace std;
vector<int> vect;
for (int nCount=0; nCount < 6; nCount++)
vect.push_back(nCount);
vector<int>::const_iterator it; // 声明一个只读迭代器
it = vect.begin(); //将它分配给向量的开头
while (it != vect.end()) //虽然还没有到达终点
{
cout << *it << " "; // 打印它指向的元素的值
++it; // 并迭代到下一个元素
}
cout << endl;
}
这将打印以下内容:
0 1 2 3 4 5
迭代list
现在让我们用列表做同样的事情:
#include <iostream>
#include <list>
int main()
{
using namespace std;
list<int> li;
for (int nCount=0; nCount < 6; nCount++)
li.push_back(nCount);
list<int>::const_iterator it; //声明一个迭代器
it = li.begin(); // 将其分配到列表的开头
while (it != li.end()) //虽然还没有到达终点
{
cout << *it << " "; //打印它指向的元素的值
++it; // 并迭代到下一个元素
}
cout << endl;
}
这打印:
0 1 2 3 4 5
请注意,代码几乎与矢量大小写相同,即使矢量和列表具有几乎完全不同的内部实现!
迭代填充
在下面的示例中,我们将从6个数字创建一个集合,并使用迭代器来打印集合中的值:
#include <iostream>
#include <set>
int main()
{
using namespace std;
set<int> myset;
myset.insert(7);
myset.insert(2);
myset.insert(-6);
myset.insert(8);
myset.insert(1);
myset.insert(-4);
set<int>::const_iterator it; //声明一个迭代器
it = myset.begin(); // 将其分配给集合的开头
while (it != myset.end()) //虽然还没有到达终点
{
cout << *it << " "; // 打印它指向的元素的值
++it; // 并迭代到下一个元素
}
cout << endl;
}
该程序产生以下结果:
-6 -4 1 2 7 8
请注意,虽然填充集合与填充矢量和列表的方式不同,但用于迭代集合元素的代码基本相同。
迭代Maps
这个有点棘手。Maps和multimaps采用成对元素(定义为std :: pair)。我们使用make_pair()辅助函数来轻松创建对。std :: pair允许通过第一个和第二个成员访问该对的元素。在我们的地图中,我们首先使用第一个键作为键,然后使用第二个作为键。
#include <iostream>
#include <map>
#include <string>
int main()
{
using namespace std;
map<int, string> mymap;
mymap.insert(make_pair(4, "apple"));
mymap.insert(make_pair(2, "orange"));
mymap.insert(make_pair(1, "banana"));
mymap.insert(make_pair(3, "grapes"));
mymap.insert(make_pair(6, "mango"));
mymap.insert(make_pair(5, "peach"));
map<int, string>::const_iterator it; //声明一个迭代器
it = mymap.begin(); //将它分配给向量的开头
while (it != mymap.end()) //虽然还没有到达终点
{
cout << it->first << "=" << it->second << " "; // 打印它指向的元素的值
++it; // 并迭代到下一个元素
}
cout << endl;
}
该程序产生结果:
1 =香蕉2 =橙色3 =葡萄4 =苹果5 =桃子6 =芒果
请注意迭代器如何轻松地遍历容器的每个元素。您根本不必关心Maps如何存储其数据!
Conclusion
迭代器提供了一种简单的方法来逐步执行容器类的元素,而无需了解容器类的实现方式。当与STL的算法和容器类的成员函数结合使用时,迭代器变得更加强大。在下一课中,您将看到使用迭代器将元素插入到列表中的示例(它不提供重载的operator []来直接访问其元素)。
值得注意的一点是:迭代器必须基于每个类实现,因为迭代器确实需要知道如何实现类。因此迭代器总是绑定到特定的容器类。