迭代器
C++中,迭代器就是类似于指针的对象,但比指针的功能更丰富,它提供了对对象的间接访问,每个迭代器对象代表容器中一个确定的地址。
举个例子:
void test()
{
vector<int> vv={1,2,3,4,5};
for(vector<int>::iterator it=vv.begin();it!=vv.end();it++)
{
cout<<*it<<" ";
}
cout<<endl;
}
//1 2 3 4 5
迭代器的分类
正向迭代器
只能使用++运算符从左向右遍历容器,每次沿容器向右移动一个元素。
容器名<元素类型>::iterator 迭代器名; // 正向迭代器。
容器名<元素类型>::const_iterator 迭代器名; // 常正向迭代器。
相关的成员函数:
iterator begin();
const_iterator begin();
const_iterator cbegin(); // 配合auto使用。
iterator end();
const_iterator end();
const_iterator cend();
双向迭代器
具备正向迭代器的功能,还可以反向(从右到左)遍历容器(也是用++),不管是正向还是反向遍历,都可以用--让迭代器后退一个元素。
容器名<元素类型>:: reverse_iterator 迭代器名; // 反向迭代器。
容器名<元素类型>:: const_reverse_iterator 迭代器名; // 常反向迭代器。
相关的成员函数:
reverse_iterator rbegin();
const_reverse_iterator crbegin();
reverse_iterator rend();
const_reverse_iterator crend();
随机访问迭代器
具备双向迭代器的功能,还支持以下操作:
用于比较两个迭代器相对位置的关系运算(<、<=、>、>=)。
迭代器和一个整数值的加减法运算(+、+=、-、-=)。
支持下标运算(iter[n])。
迭代器的失效问题
vector迭代器失效的几种情况
1. 扩容可能引起迭代器失效(insert,assign,push_back都可能引起扩容)
void test3()
{
vector<int>v;
for (int i = 0; i < 5; i++)
v.push_back(i);
cout << "容量:" << v.capacity() << endl;
cout << "大小:" << v.size() << endl;
auto it = v.begin();
int size = v.capacity(); //记录插入数据之前的容量
v.push_back(6);
v.push_back(7);
cout << "容量:" << v.capacity() << endl;
cout << "大小:" << v.size() << endl;
if (v.capacity() > size) //判断是否扩容
{
cout << "扩容了!" << endl;
}
while (it != v.end())
{
cout << *it << " ";
it++;
}
}
分析:
这是为什么呢?不难发现,vector是序列式容器,在内存中是一块连续的内存,当内存不足需要扩容时,需要将原来的空间释放掉,重新开辟一片连续的空间,所以这样操作原来的迭代器相当于非法操作内存,如果容器没有扩容的话,只有it=v.end()的迭代器失效,那怎么解决呢?只需要在每次在操作迭代器前重新给迭代器赋值。
2.容器容量变化造成的迭代器失效
void test2()
{
vector<int> vv;
for (int i = 0; i < 10; i++)
vv.push_back(i);
cout << "vv.size()=" << vv.size() << endl;
cout << "vv.capacity()=" << vv.capacity() << endl;
auto it = vv.begin();
cout << "after shrink_to_fit()" << endl;
vv.shrink_to_fit();
cout << "vv.size()=" << vv.size() << endl;
cout << "vv.capacity()=" << vv.capacity() << endl;
cout << *it << endl;
}
3.被擦除的元素及之后的所有元素失效,包括end()
4. 被擦除元素及end()
void test3()
{
vector<int> vv;
for (int i = 0; i < 10; i++)
vv.push_back(i);
auto it = vv.end();
cout << "after pop_back()" << endl;
vv.pop_back();
cout << *it << endl;
}