什么是迭代器
迭代器是一种面向对象的广义指针,用于指向容器中或流中的对象。可以看做是一种指向数据的指针。
何谓迭代器失效
迭代器失效是一种现象,由特定操作引发,这些特定操作对容器进行操作,使得迭代器不指向容器内的任何元素,或者使得迭代器指向的容器元素发生了改变。
【Note】后一种取决于编译器,部分编译器会将此种情况也视为迭代器失效,部分编译器并不视为失效)
可能引起迭代器失效的操作
因为不同的容器,迭代器不尽相同。
可以引起vector
迭代器失效的相同操作不一定会导致list
的迭代器失效
可能引起迭代器失效的操作` | |
---|---|
1 | 插入元素/扩容引起的迭代器指向的元素或者空间发生变化,导致迭代器失效 |
2 | 删除元素使得某些元素次序发生变化使得原本指向某元素的迭代器不再指向希望指向的元素。 |
3 | 容器空间被释放导致存放原容器元素的空间不再有效,使得指向原空间的迭代器失效。 |
4 | 容器元素整体“迁移”导致存放原容器元素的空间不再有效,使得指向原空间的迭代器失效。 |
list的迭代器失效
list的底层是带头结点的双向循环链表:
因此可以使list迭代器失效的操作只有erase
(删除)操作,且失效的迭代器仅仅是被删除节点的迭代器,其他迭代器并不受影响,依然有效。
至于为什么其它迭代器不受影响的原因如下图所示:
我们可以很清楚的看到迭代器3指向的元素不存在了!而其他迭代器指向的元素仍存在,所以仅有被删元素的迭代器失效,其他迭代器不受影响
如何解决list的迭代器失效问题
我们可以查看list::erase
的官方文档说明:
这两个删除方法的返回值都是被删节点的后继节点的迭代器!
iterator erase(iterator it);
iterator erase(iterator first, iterator last);
因此,我们在删除后,需要的话可以利用这个返回值进行后续操作
vector的迭代器失效
vector的底层是可动态扩容的数组:
该数组插入/删除元素都会引起插入/删除位置之后的元素发生挪动。删除会使删除位置之后的元素全部前移,插入会使插入位置之后的元素全部后移。
因此删除/插入操作都会使被操作的元素对应的迭代器失效,会导致操作位置之后的迭代器全部失效!
插入图示如下:
可以看到插入位置对应的迭代器及其之后的迭代器指向的元素全部发生改变,全部失效
删除图示如下:
同理,不再赘述。
可能引起vector迭代器失效的操作 | |
---|---|
1 | resize、reserve、insert、assign、push_back等可以引起底层空间发生变化的操作 |
2 | erase删除操作 |
如何解决vector的迭代器失效问题
似乎没有别的办法,我们只能牢记这些可能导致迭代器失效的操作,在使用迭代器前,牢记更新迭代器(重新赋值)即可