1. 迭代器概念
- 迭代器是一种对象,它能够
用来遍历标准模板库容器中的部分或全部元素
,每个迭代器对象代表容器中的确定的地址。迭代器修改了常规指针的接口
,所谓迭代器是一种概念上的抽象:那些行为上像迭代器的东西都可以叫做迭代器。然而迭代器有很多不同的能力,它可以把抽象容器和通用算法有机的统一起来
。 - vector容器中的接口link:
2. 迭代器失效
迭代器失效有两个层面的意思:
- 无法通过迭代器++,- -操作遍历整个stl容器。记作: 第一层失效。
- 无法通过迭代器存取迭代器所指向的内存。 记作: 第二层失效。
3.vector迭代器失效
迭代器的失效问题:对容器的操作影响了元素的存放位置,称为迭代器失效
。
失效情况:
- 当容器调用
erase()
方法后,当前位置到容器末尾元素的所有迭代器全部失效。 - 当容器调用
insert()
方法后,当前位置到容器末尾元素的所有迭代器全部失效。 - 如果容器扩容,在其他地方重新又开辟了一块内存。原来容器底层的内存上所保存的迭代器全都失效了。(深拷贝带来的迭代器失效问题)
- 不同容器的迭代器,是不能进行比较运算的。
4.模拟vector中的erase()/insert()
这里只附上部分代码
insert()
:
iterator insert(iterator pos, const T&x)
{
assert(pos <= _finish&&pos >= _start);
//保存一份相对位置,防止空间不够增容导致迭代器失效
size_t inpos = pos - _start;
check_capacity();
//对pos相对位置进行更新
pos = _start + inpos;
iterator last = _finish;
while (last != pos)//往后挪动空出pos位置
{
*last = *(last - 1);
last--;
}
*pos = x;
_finish++;
//防止迭代器失效问题
return pos;
}
erase()
:
iterator erase(iterator pos)
{
assert(pos >= _start&&pos < _finish);
iterator temp_pos = pos;
//_finish-1是因为区间是左闭右开[)的,-1是为了指向有效数据。
while (pos < _finish-1)
{
*pos = *(pos + 1);
pos++;
}
_finish--;
//返回的是删除结点的下一个位置
return temp_pos;
}
void reserve(size_t n)
{
if (n > capacity())
{
iterator temp = new T[n];
//记录大小
size_t old_size = size();
iterator begin_start = _start;
iterator begin_temp=temp;
while (begin_start != _finish)
{
//深拷贝
*begin_temp= *begin_start;
begin_start++;
begin_temp++;
}
delete[] _start;//释放原来的空间
_start = temp;//指向新的空间
temp = nullptr;//防止析构自定义类型
//防止迭代器失效
_finish = _start + old_size;
_end_of_storge = _start + n;
}
}
5.代码图解
由代码可知,插入和删除有返回值
,所以平时在插入删除的时候应该将迭代器更新
:
iter = v.insert(iter, 1);
iter = v.erase(iter);
6. 代码示例
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void test_vector2()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.insert(v.begin(),0);
v.insert(v.end(), 5);
auto it = find(v.begin(),v.end(), 3);
if (it != v.end())
v.insert(it, 30);
else
cout << "没有找到" << endl;
//如何删除掉3?
//如果不加:it = find(v.begin(), v.end(), 3)这一句的话,因为it经历了上面的insert之后,it就成了失效的迭代器
//怎么理解这儿的迭代器失效呢?
//迭代器失效是由insert(因为insert时可能会增容)引发的,这时候会出现野指针,也就是迭代器失效
//所以,在insert之后,就不要再去访问迭代器了,因为insert之后可能会增容,从而导致迭代器失效,为了避免这个问题,我们可以重新找这个迭代器的位置,这样就不会引发迭代器失效问题了
/*it = find(v.begin(), v.end(), 3);
v.erase(it);*/
//要求删除所给数据中所有的偶数:(这种情况下,也会导致迭代器失效,具体原因如下图分析:)
it = v.begin();
while (it != v.end())
{
if (*it % 2 == 0)
v.erase(it);
it++;
}
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
}
int main()
{
/*test_vector1();*/
test_vector2();
system("pause");
return 0;
}
7.总结
删除元素erase():
- 指向vector或string中删除点之后位置的迭代器、引用和指针都会失效。指向之前的元素则仍任有效
- 删除deque中除首尾位置之外的任何元素,都会使所有的迭代器、引用及指针失效。
- 对于map、set等会导致指向被删除元素迭代器失效,因此在用迭代器循环删除时,可以用it++
- 注:当删除元素时,尾后迭代器(end)总是会失效,因此尽量不要保存end返回的迭代器。
添加元素insert():
- 如果vector或string的存储空间被重新分配,则全部迭代器、引用及指针都失效。
- 如果未重新分配,则指向插入之前的有效,之后的失效。
- 对于deque,插入到任何除首尾之外的位置,都会使其他迭代器失效。
- deque如果在首尾位置插入,则迭代器失效,但指向存在的元素的引用和指针不会失效。