在STL容器类(Vector,Dequeue,list,map,multimap,set,multiset)上操作时,Iterator失效的常用规则是什么?是否可以对C ++ STL程序员在处理容器及其迭代器时必须注意的一些一般规则/指南进行分类和总结?
答案 0 :(得分:6)
这些规则是特定于容器的。事实上,这些是决定您使用哪个容器的重要标准。
例如,插入对象时,std::vector
的迭代器可能会失效(取决于插入对象的位置以及是否进行重新分配),并且在迭代器之前删除对象时它们会失效。 std::list
没有此问题。插入和删除对象(迭代器指向的对象除外)不会使迭代器失效。
SGI就此提供了良好的documentation。
答案 1 :(得分:3)
失效规则的灵感来自用于实现这些容器的非常基本的数据结构和算法。如果您不打算学习基础知识,那么您需要记住迭代器文档。
C ++标准以使用实现简单C指针的方式定义iterator
的行为。它不需要库实际使用指针;它只是使它成为可能。
基本上,如果操作导致底层存储元素(vector
中使用的堆数组,list
中使用的链表节点,或者使用的树节点),则迭代器无效一个map
或set
)要被释放,或者被移植到不同的内存位置。
通常通过从动态内存(堆)中分配数组来实现vector
。为了减少重新分配的数量,总是为阵列分配一些松弛,即最初未使用的空间。随着元素被添加到数组中,松弛空间正在用完。当所有松弛空间都被占用并且需要插入新元素时,将分配具有更大尺寸的新阵列。这将导致指向旧数组的所有迭代器失效。
同样,当从vector
中删除元素时,这将导致所有后续元素向前复制。指向移位元素的迭代器仍将引用数组中的相同索引,但该索引现在包含不同的元素。这也是失效的一个例子。
对于list
,map
和set
,树节点或列表节点在其包含的元素被删除之前一直有效。请注意,指向无效节点的迭代器不能用于任何内容;甚至没有迭代器递增/递减。这是因为在链表或树实现中,迭代器依赖于存储在节点本身中的子指针。
为了始终保证正确的操作,与使用简单的数据结构相比,标准的措辞更加严格(矛盾的是,图书馆实施者可以更自由地使用更高级的数据结构)。例如,请参阅http://c2.com/cgi/wiki?IteratorInvalidationProblem和http://www.threadingbuildingblocks.org/codesamples.php。