迭代器是STL中提供的对容器中对象的访问方法。它就像指针,可以用*运算符获取数据,可以使用++,--对迭代器进行操作。
迭代器的范围可以由begin()和end()这两个函数获得,begin()返回指向容器中的第一个元素的迭代器,end()返回指向容器的最后一个元素的下一个位置的迭代器。
迭代器是如何访问到容器中的数据呢?
在list中,定义了一个名字是__list__iterator的结构体,里面实现了一系列类似于指针操作的重载函数。
template<class T, class Ref, class Ptr>
struct __list_iterator {
typedef __list_iterator<T, T&, T*> iterator;
typedef __list_iterator<T, const T&, const T*> const_iterator;
typedef __list_iterator<T, Ref, Ptr> self;
...
link_type node; //一个链表结点
__list_iterator(link_type x) : node(x) {}
__list_iterator() {}
__list_iterator(const iterator& x) : node(x.node) {}
bool operator==(const self& x) const { return node == x.node; }
bool operator!=(const self& x) const { return node != x.node; }
reference operator*() const { return (*node).data; }
...
self& operator++() {
node = (link_type)((*node).next);
return *this;
}
self operator++(int) {
self tmp = *this;
++*this;
return tmp;
}
self& operator--() {
node = (link_type)((*node).prev);
return *this;
}
self operator--(int) {
self tmp = *this;
--*this;
return tmp;
}
};
再看list类中:
template <class T, class Alloc = alloc>
class list {
protected:
...
public:
typedef __list_iterator<T, T&, T*> iterator;
typedef __list_iterator<T, const T&, const T*> const_iterator;
...
protected:
link_type node; //这是链表的头结点
public:
list() { empty_initialize(); }
iterator begin() { return (link_type)((*node).next); }
const_iterator begin() const { return (link_type)((*node).next); }
iterator end() { return node; }
const_iterator end() const { return node; }
}
可以看到begin()返回的是头结点的下一个结点,而end()返回的是头结点,表示最后一个元素的下一个元素,这也是STL中的list要带头结点的重要原因。
有了头结点,__list__iterator中又实现了++,-- ,*的重载,这样就可以很方便地像指针一样遍历链表啦。
其它容器中迭代器的结构类似。但vector中却不是这样的。
在vector中:
template <class T, class Alloc = alloc>
class vector {
public:
typedef T value_type;
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef value_type* iterator;
typedef const value_type* const_iterator;
protected:
iterator start;
iterator finish;
iterator end_of_storage;
...
public:
iterator begin() { return start; }
const_iterator begin() const { return start; }
iterator end() { return finish; }
const_iterator end() const { return finish; }
...
}
可以看到vector的iterator其实就是某种数据类型的指针,因为vector的底层就是数组,start指向一段从内存中开辟的连续空间,指针本身就可以遍历它,就不需要再去实现一些函数的重载啦。
------------------------------------------------------------------------------------------------------
迭代器的使用:
#include<iostream>
#include<stdlib.h>
#include<vector>
using namespace std;
int main()
{
vector<int> vt;
vt.push_back(1);
vt.push_back(2);
vt.push_back(3);
vt.push_back(4);
vector<int>::iterator it = vt.begin();
while(it != vt.end())
{
cout<<*it<<" ";
++it;
}
system("pause");
return 0;
}
使用迭代器要注意迭代器失效的问题,举一个例子:
<pre name="code" class="cpp">#include<iostream>
#include<stdlib.h>
#include<list>
using namespace std;
int main()
{
list<int> ls;
ls.push_back(1);
ls.push_back(2);
ls.push_back(3);
ls.push_back(4);
list<int>::iterator it = ls.begin();
while(it != ls.end())
{
if(*it % 2 ==0)
ls.erase(it);
++it;
}
system("pause");
return 0;
}
删除list中是2的倍数的结点,但是程序一运行就会崩溃。
问题出在++it,把2删除了之后,it指向的空间已经被释放了,再++it,程序当然会崩溃。
解决方案:
1)
#include<iostream>
#include<stdlib.h>
#include<list>
using namespace std;
int main()
{
list<int> ls;
ls.push_back(1);
ls.push_back(2);
ls.push_back(3);
ls.push_back(4);
list<int>::iterator it = ls.begin();
while(it != ls.end())
{
list<int>::iterator tmp = it;
++it;
if(*tmp % 2 ==0)
ls.erase(tmp);
}
system("pause");
return 0;
}
2)
list<int>::iterator it = ls.begin();
while(it != ls.end())
{
if(*it % 2 ==0)
it = ls.erase(it);
else
++it;
}
因为erase会返回指向下一个结点的迭代器。