小编典典

C++ 容器的迭代器失效规则

all

C++ 容器的迭代器失效规则是什么?

注意: 这个问答是期中的一个条目。关于问题本身的元讨论应该发布在开始所有这些的元问题上,而不是在这里。)


阅读 105

收藏
2022-03-06

共1个答案

小编典典

C++17 (所有参考资料均来自 CPP17 - n4659的最终工作草案)


插入

序列容器

  • vector:如果新容量大于旧容量,函数insert, emplace_back,会导致重新分配。重新分配使引用序列中元素的所有引用、指针和迭代器无效。如果没有发生重新分配,则插入点之前的所有迭代器和引用仍然有效。[26.3.11.5/1] 对于函数,重新分配使所有引用序列中元素的引用、指针和迭代器无效。在调用之后发生的插入期间不会发生重新分配,直到插入会使向量的大小大于 的值。[26.3.11.3/6]emplace``push_back
    reserve``reserve()``capacity()

  • deque:在双端队列中间插入会使所有迭代器和对双端队列元素的引用无效。在双端队列的任何一端插入都会使双端队列的所有迭代器无效,但不会影响对双端队列元素的引用的有效性。[26.3.8.4/1]

  • list:不影响迭代器和引用的有效性。如果抛出异常,则没有任何影响。[26.3.10.4/1]。
    此规则涵盖insert, emplace_front, emplace_back, emplace,
    push_front,函数。push_back

  • forward_list: 的任何重载都insert_after不会影响迭代器和引用的有效性 [26.3.9.5/1]

  • array通常,数组的迭代器在数组的整个生命周期内都不会失效。然而,应该注意的是,在交换期间,迭代器将继续指向同一个数组元素,因此会改变它的值。

关联容器

  • All Associative Containersinsertandemplace成员不应影响迭代器的有效性和对容器的引用 [26.2.6/9]

无序关联容器

  • All Unordered Associative Containers: 重新散列使迭代器无效,更改元素之间的顺序,并更改元素出现在哪些桶中,但不会使指针或对元素的引用无效。[26.2.7/9] and成员不应影响对容器元素的引用的有效性,但可能会使容器的所有迭代器无效
    。[26.2.7/14] and成员不应影响迭代器的有效性,如果
    ,其中是插入操作之前容器中的元素数,是插入的元素数,是容器的桶数,并且是集装箱的最大装载系数。[26.2.7/15]insert``emplace
    insert``emplace``(N+n) <= z * B``N``n``B``z

  • All Unordered Associative Containers:在合并操作的情况下(例如,a.merge(a2)),引用被转移元素的迭代器和所有引用的迭代器a都将失效,但剩余元素的迭代器a2将保持有效。(表 91——无序关联容器要求)

容器适配器

  • stack: 从底层容器继承
  • queue: 从底层容器继承
  • priority_queue: 从底层容器继承

擦除

序列容器

  • vector:在擦除点或之后的函数erase和无效迭代器和引用。pop_back[26.3.11.5/3]

  • deque:擦除 a 的最后一个元素的擦除操作deque仅使过去的迭代器和所有迭代器以及对被擦除元素的引用无效。擦除 a 的第一个元素但不擦除最后一个元素的擦除操作deque只会使迭代器和对被擦除元素的引用无效。既不擦除 a 的第一个元素也不擦除最后一个元素的擦除操作deque会使过去的迭代器和所有迭代器以及对deque. [注:pop_frontpop_back是擦除操作。㈥攅第注] [26.3.8.4/4]

  • list:仅使迭代器和对已擦除元素的引用无效。[26.3.10.4/3]。这适用于erase, pop_front, pop_back,clear函数。
    removeremove_if成员函数:擦除列表迭代器引用的列表i中满足以下条件的所有元素:*i == value, pred(*i) != false. 仅使迭代器和对已擦除元素的引用无效 [26.3.10.5/15]。成员函数 - 从迭代器引用的每个连续
    unique的相等元素组中擦除除第一个元素之外的所有元素(对于不带参数的唯一版本)或i``[first + 1, last)``*i == *(i-1)``pred(*i, *(i - 1))(对于带有谓词参数的唯一版本)成立。仅使迭代器和对已擦除元素的引用无效。[26.3.10.5/19]

  • forward_list:erase_after应仅使迭代器和对已擦除元素的引用无效。[26.3.9.5/1]。
    removeremove_if成员函数 - 删除列表迭代器 i 引用的列表中的所有元素,其中满足以下条件:*i == value(for
    remove()),pred(*i)为 true (for
    remove_if())。仅使迭代器和对已擦除元素的引用无效。[26.3.9.6/12]。
    unique成员函数 - 从迭代器 i 引用的每个连续的相等元素组中删除除第一个元素之外的所有元素,范围为 [first + 1, *i == *(i-1)last pred(*i, *(i - 1)))论点)成立。仅使迭代器和对已擦除元素的引用无效。[26.3.9.6/16]

  • All Sequence Containers:clear使所有引用 a 元素的引用、指针和迭代器无效,并可能使过去的迭代器无效(表 87 - 序列容器要求)。但是对于forward_list,clear不会使过去的迭代器无效。[26.3.9.5/32]

  • All Sequence Containers:assign使所有引用容器元素的引用、指针和迭代器无效。对于vectorand deque,也使过去的迭代器无效。(表 87——序列容器要求)

关联容器

  • All Associative Containerserase成员应仅使迭代器和对已擦除元素的引用无效 [26.2.6/9]

  • All Associative Containers:extract成员只使被移除元素的迭代器失效;指向已删除元素的指针和引用仍然有效 [26.2.6/10]

容器适配器

  • stack: 从底层容器继承
  • queue: 从底层容器继承
  • priority_queue: 从底层容器继承

与迭代器失效有关的一般容器要求:

  • 除非另有规定(明确地或通过根据其他函数定义函数),调用容器成员函数或将容器作为参数传递给库函数不应使该容器内对象的迭代器无效或更改其值. [26.2.1/12]

  • 任何swap()函数都不会使引用被交换容器元素的任何引用、指针或迭代器无效。[ 注意: end() 迭代器不引用任何元素,因此它可能会失效。——第注] [26.2.1/(11.6)]

作为上述要求的示例:

  • transform算法:opandbinary_op函数不应使迭代器或子范围无效,或修改范围 [28.6.4/1] 中的元素

  • accumulate算法:在 [first, last] 范围内,binary_op既不修改元素也不使迭代器或子范围无效 [29.8.2/1]

  • reduce算法:binary_op 既不能使迭代器或子范围无效,也不能修改范围 [first, last] 中的元素。[29.8.3/5]

等等…

2022-03-06