前言
对容器进行插入删除操作时,迭代器失效是什么意思?
- 对迭代器解引用,该地址上存放的值不再是操作前的值。(容易引起误解的一点是,有人把迭代器失效理解为无法访问)
容器分类
STL容器按照数据结构可以大致分为以下几类:
- 数组型,比如vector、deque
- 链表型,比如list
- 树型,比如map,set,multimap,multiset
下面简单讲讲插入、删除对以上三种容器的影响
数组型容器
- 插入时,若size < capacity,则插入点及之后的迭代器全部失效(插入后,所有旧迭代器仍然能访问,若以值是否在操作前后发生变化为考量,则仅有原先的end迭代器必定失效)。
- 插入时,若size == capacity,则所有迭代器失效(插入后,所有元素分配到新的内存空间,不仅迭代器解引用的值发生变化,内存地址也发生了变化)。
- 删除时,由于内存空间连续,会引起删除点之后的元素全部往前移动一个位置,因此删除点及之后的迭代器全部失效,可用以下代码正确迭代:
- deque有些特殊,除了头尾两端,在任何地方插入和删除元素都将导致内存重新分配。
for (iter = cont.begin(); iter != cont.end();)
{
(*it)->doSomething();
if (shouldDelete(*iter))
iter = cont.erase(iter);
else
++iter;
}
链表型容器
- 插入时,不引起迭代器失效。
- 删除时,只有当前迭代器失效。由于内存空间不连续,可用以下代码正确迭代(由于erase方式同样返回下一个有效的迭代器,也可以使用与数组型容器同样的方法正确迭代):
for (iter = cont.begin(); it != cont.end();)
{
(*iter)->doSomething();
if (shouldDelete(*iter))
cont.erase(iter++);
else
++iter;
}
树型容器
由于底层数据结构是红黑树,因此插入删除不影响其他节点,在插入时,红黑树会旋转重建,不引起迭代器失效。删除时,可用以下代码正确遍历:
for (iter = cont.begin(); it != cont.end();)
{
(*iter)->doSomething();
if (shouldDelete(*iter))
cont.erase(iter++);
else
++iter;
}
扩展
- 为什么queue、stack没有迭代器?
- 迭代器用于对数据结构中的元素进行顺序访问或随机访问。而队列queue只能从头部取,从尾部存,不能遍历(遍历可以理解为只读,而queue做不到只读,同样stack也不行)。