Iterator invalidation rules
C++容器的迭代器失效规则是什么?
最好是以摘要列表格式。
C++ 03(源代码:迭代器失效规则(C++ 03))
插入顺序容器
vector :插入点之前的所有迭代器和引用都不受影响,除非新容器的大小大于以前的容量(在这种情况下,所有迭代器和引用都无效)[23.2.4.3/1]deque :所有迭代器和引用都无效,除非插入的成员位于deque的末尾(前面或后面)(在这种情况下,所有迭代器都无效,但对元素的引用不受影响)[23.2.1.3/1]list :所有迭代器和引用不受影响[23.2.2.3/1]
关联容器
[multi]{set,map} :所有迭代器和引用不受影响[23.1.2/8]
容器适配器
stack :继承自底层容器queue :继承自底层容器priority_queue :继承自底层容器
擦除
顺序容器
vector :擦除点后的每个迭代器和引用都无效[23.2.4.3/3]deque :所有迭代器和引用都是无效的,除非被删除的成员位于deque的末尾(前面或后面)(在这种情况下,只有迭代器和对被删除成员的引用是无效的)〔23.2.1.3/4〕。list :只有迭代器和对已擦除元素的引用无效[23.2.2.3/3]
关联容器
[multi]{set,map} :只有迭代器和对已擦除元素的引用无效[23.1.2/8]
容器适配器
stack :继承自底层容器queue :继承自底层容器priority_queue :继承自底层容器
调整大小
vector :根据插入/擦除[23.2.4.2/6]deque :根据插入/删除[23.2.1.2/1]list :根据插入/删除[23.2.2.2/1]
注释1
Unless otherwise specified (either
explicitly or by defining a function
in terms of other functions), invoking
a container member function or passing
a container as an argument to a
library function shall not invalidate
iterators to, or change the values of,
objects within that container.
[23.1/11]
注释2
在C++ 2003中还不清楚"结束"迭代器是否符合上述规则;无论如何,你应该假定它们是(实际上是这样的情况)。
注释3指针无效化规则与引用无效化规则相同。
C++ 11(源代码:迭代器失效规则(C++0x))
插入顺序容器
vector :插入点之前的所有迭代器和引用都不受影响,除非新容器的大小大于以前的容量(在这种情况下,所有迭代器和引用都无效)[23.3.6.5/1]deque :所有迭代器和引用都无效,除非插入的成员位于deque的末尾(前面或后面)(在这种情况下,所有迭代器都无效,但对元素的引用不受影响)[23.3.3.4/1]list :所有迭代器和引用都不受影响[23.3.5.4/1]forward_list :所有迭代器和引用都不受影响(适用于insert_after 〔23.3.4.5/1〕。array (不适用)
关联容器
[multi]{set,map} :所有迭代器和引用不受影响[23.2.4/9]
未排序的关联容器
unordered_[multi]{set,map} :所有迭代器在重新刷新时都无效,但引用不受影响[23.2.5/8]。如果插入不会导致容器大小超过z * B ,则不会发生重洗,其中z 是最大负载系数,B 是当前桶数。[23.2.5/14 ]
容器适配器
stack :继承自底层容器queue :继承自底层容器priority_queue :继承自底层容器
擦除
顺序容器
vector :擦除点或之后的每个迭代器和引用都无效[23.3.6.5/3]deque :删除最后一个元素只会使迭代器和对已删除元素的引用以及对结束迭代器的引用失效;删除第一个元素只会使迭代器和对已删除元素的引用失效;删除任何其他元素会使所有迭代器和引用(包括对结束迭代器的引用)失效[23.3.3.4/4]list :只有迭代器和对已擦除元素的引用无效[23.3.5.4/3]forward_list :只有迭代器和对已擦除元素的引用无效(适用于erase_after 〔23.3.4.5/1〕。array (不适用)
关联容器
[multi]{set,map} :只有迭代器和对已擦除元素的引用无效[23.2.4/9]
无序关联容器
unordered_[multi]{set,map} :只有迭代器和对已擦除元素的引用无效[23.2.5/13]
容器适配器
stack :继承自底层容器queue :继承自底层容器priority_queue :继承自底层容器
调整大小
vector :根据插入/擦除[23.3.6.5/12]deque :根据插入/删除[23.3.3.3/3]list :根据插入/删除[23.3.5.3/1]forward_list :根据插入/删除[23.3.4.5/25]array (不适用)
注释1
Unless otherwise specified (either
explicitly or by defining a function
in terms of other functions), invoking
a container member function or passing
a container as an argument to a
library function shall not invalidate
iterators to, or change the values of,
objects within that container.
[23.2.1/11]
注释2
no swap() function invalidates any
references, pointers, or iterators
referring to the elements of the
containers being swapped. [ Note: The
end() iterator does not refer to any
element, so it may be invalidated.
—end note ] [23.2.1/10]
注释3
除了上述关于
可能值得补充的是,只要所有的插入都是通过这个迭代器执行的,并且没有其他独立的迭代器失效事件发生,任何类型的插入迭代器(
例如,当使用
同样,这只适用于通过插入迭代器本身执行的插入。如果迭代器失效事件是由容器上的某个独立操作触发的,那么插入迭代器也将根据一般规则失效。
例如,此代码
1 2 3 4 5 6 | std::vector<int> v(10); std::vector<int>::iterator it = v.begin() + 5; std::insert_iterator<std::vector<int> > it_ins(v, it); for (unsigned n = 20; n > 0; --n) *it_ins++ = rand(); |
保证在向量中执行有效的插入序列,即使向量"决定"在此过程中的某个位置重新分配。迭代器
C++ 17(所有参考文献均来自CPP17-N465 9的最终工作草案)好的。插入
顺序容器好的。
vector :新容量大于旧容量时,insert 、emplace_back 、emplace 、push_back 等功能引起重新分配。重新分配会使引用序列中元素的所有引用、指针和迭代器失效。如果没有重新分配发生这种情况时,插入点之前的所有迭代器和引用都保持有效。[23.3.11.5/1 ]对于reserve 函数,重新分配会使引用序列中元素的所有引用、指针和迭代器失效。在调用reserve() 之后发生的插入期间,在插入将使向量的大小大于capacity() 的值之前,不应发生重新分配。[23.3.113/ 6 ]好的。deque :在deque中间插入将使所有迭代器和对deque元素的引用失效。deque两端的插入会使deque的所有迭代器失效,但不会影响deque元素引用的有效性。[23.3.84/ 1 ]好的。list :不影响迭代器和引用的有效性。如果抛出异常,则没有任何效果。[23.3.104/1 ]。本规则涵盖了insert 、emplace_front 、emplace_back 、emplace 、push_front 、push_back 功能。好的。forward_list :insert_after 的重载不影响迭代器和引用的有效性[26.3.9.5/1]好的。array :通常,数组的迭代器在数组的整个生命周期内都不会失效。不过,应该注意,在交换期间,迭代器将继续指向同一数组元素,从而更改其值。好的。
关联式容器好的。
All Associative Containers :insert 和emplace 成员不应影响迭代器和对容器的引用的有效性[26.2.6/9]
无序关联容器好的。
All Unordered Associative Containers :重新刷新将使迭代器失效,更改元素之间的顺序,以及buckets元素出现在其中的更改,但不会使指向元素或对元素的引用失效。[22.2.7/9 ]insert 和emplace 成员不影响对容器元素的引用的有效性,但可能使容器的所有迭代器失效。[22.2.7/14 ]insert 和emplace 成员不影响迭代器的有效性,如果(N+n) <= z * B ,其中N 是插入操作之前容器中的元素数,N 是插入的元素数,B 是容器的桶数,z 是容器的最大值。负载因子[22.2.7/15 ]好的。-
All Unordered Associative Containers 案例:在一个merge操作(例如,a.merge(a2) ),referring迭代器的元素的迭代器的转移和全referring到a 将invalidated,但剩余的元素的迭代器在a2 将保持有效。(table 91结合无序容器的要求)/好的。
集装箱adaptors
/好的。
-
stack :继承从标的容器 -
queue :继承从标的容器 -
priority_queue :继承从标的容器
erasure
序列容器
/好的。
-
vector :函数的erase 和pop_back invalidate迭代器和证明人.或在点的erase。。。。。。。26.3.11.5 / [ 3 ]/好的。
-
deque :erase操作erases那最后的一元一deque invalidates只读的过去的end迭代器和迭代器的全和证明人的erased元素。安erase操作,erases第一元一deque 但不是最后一个元素的迭代器invalidates只读和证明人的erased元素。安erase操作,erases不是第一个或最后一个元素的元素的一个deque invalidates在过去的end迭代器和迭代器的全和证明人的所有元素的deque 。。。。。。。 [注:pop_front 和pop_back 是erase操作。端26.3.8.4 /注] [ 4 ]/好的。
-
list :invalidates只读的迭代器和证明人的erased元素。26.3.10.4 / [ 3 ]。这applies到erase ,pop_front ,pop_back ,clear 函数。remove 和remove_if 成员函数:erases所有元素在列表中所提到的列表迭代器的方法i 下面的条件:*i == value 扑克,pred(*i) != false 。。。。。。。invalidates只读的迭代器和证明人的erased元素26.3.10.5 / [ 15 ]。unique 成员函数erases全但第一元从每一个连续集团等元素的提到的由i 迭代器范围内[first + 1, last) 方法(这*i == *(i-1) 的版本与独特的好arguments)或pred(*i, *(i - 1)) (设计独特的版本号的predicate argument holds)。invalidates只读的迭代器和证明人的erased元素。26.3.10.5 / [ 19 ]/好的。
-
forward_list :erase_after 应invalidate只读的迭代器和证明人的erased元素。26.3.9.5 / [ 1 ]。remove 和remove_if 成员函数erases所有元素在列表中所提到的列表迭代器(我用的扑克,下面的条件:*i == value (remove() ),pred(*i) 是真的(remove_if() )。invalidates只读的迭代器和证明人的erased元素。26.3.9.6 / [ 12 ]。unique 成员函数erases全但第一元从每一组连续相等的元素的迭代器中提到的"我的范围中的第一个(+ 1),最后用这*i == *(i-1) (的版本与好的arguments)或pred(*i, *(i - 1)) (的版本号的predicate argument holds)。invalidates只读的迭代器和证明人的erased元素。26.3.9.6 / [ 16 ]/好的。
All Sequence Containers :clear 使引用a元素的所有引用、指针和迭代器失效,并可能使过去的结束迭代器失效(表87-序列容器要求)。但是对于forward_list ,clear 不会使结束迭代器失效。[23.3.95/ 32 ]好的。All Sequence Containers :assign 使所有引用、指针和引用容器元素的迭代器。对于vector 和deque ,也会使结束迭代器失效。(表87-顺序容器要求)好的。
关联式容器好的。
All Associative Containers :erase 成员只应使迭代器和对已删除元素的引用无效[26.2.6/9]好的。All Associative Containers :extract 成员仅使已删除元素的迭代器失效;指针和对已删除元素的引用仍然有效[26.2.6/10]好的。
容器适配器好的。
stack :继承自底层容器queue :继承自底层容器priority_queue :继承自底层容器
关于迭代器失效的一般容器要求:好的。
除非另有规定(明确地或通过用其他函数定义函数),否则调用容器成员函数或将容器作为参数传递给库函数都不会使该容器中对象的迭代器失效或更改其值。[22.2.1/12 ]好的。
没有一个
swap() 函数使引用被交换容器元素的任何引用、指针或迭代器失效。[注意:end()迭代器没有引用任何元素,因此它可能无效。-尾注][26.2.1/(11.6)]好的。
作为上述要求的示例:好的。
transform 算法:op 和binary_op 函数不能使迭代器或子范围无效,也不能修改范围[28.6.4/1]中的元素。好的。accumulate 算法:在[第一,最后]范围内,binary_op 既不能修改元素,也不能使迭代器或子范围失效[29.8.2/1]好的。reduce 算法:二进制运算既不能使迭代器或子范围无效,也不能修改范围[第一、最后]中的元素。[27.83/ 5 ]好的。
等等…好的。好啊。
由于这个问题吸引了这么多的选票,有点成为FAQ,我想最好写一个单独的答案来提及C++ 03和C++ 11之间的一个重要区别:EDCOX1 3的插入操作对迭代器和引用相对于EDCOX1、8、EDCX1、9、9的影响的有效性。上次投票的答案没有被注意到。
C++ 03:
Reallocation invalidates all the references, pointers, and iterators
referring to the elements in the sequence. It is guaranteed that no
reallocation takes place during insertions that happen after a call to
reserve() until the time when an insertion would make the size of the
vector greater than the size specified in the most recent call to
reserve().
C++ 11:
Reallocation invalidates all the references, pointers, and iterators
referring to the elements in the sequence. It is guaranteed that no
reallocation takes place during insertions that happen after a call to
reserve() until the time when an insertion would make the size of the
vector greater than the value of capacity().
因此,在C++ 03中,它不是"EDOCX1×10",如在另一个答案中所提到的,而是应该是"EDCOX1×11"。这是C++ 03不同于C++ 11的一个问题。在C++ 03中,一旦EDCOX1〔12〕导致向量的大小达到先前EDCOX1·8调用中指定的值(这可能小于当前EDCOX1 9),因为EDCOX1(8)可能导致比所要求的EDCOX1更大的9),任何后续EDCOX1(12)都可能导致重新分配并使所有迭代器失效。以及参考文献。在C++ 11中,这不会发生,并且您可以始终信任EDCOX1 OR 9,以确切地知道下一个重新分配不会在大小超过EDCOX1×9的情况下发生。
总之,如果你正在使用C++ 03向量,并且你想确保在执行插入时不会发生重新分配,那就是你以前传递给EDCOX1的参数的值8。你应该检查对EDCOX1 9调用的大小,而不是返回值,否则你可能会在"PrimTuu"上感到惊讶。重新分配。