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

发布于 2024-11-16 09:32:55 字数 390 浏览 2 评论 0原文

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

(Note: This Q&A is an entry in Stack Overflow's C++ FAQ. Meta-discussion about the question itself should be posted on the Meta question that started all of this, not here.)

What are the iterator invalidation rules for C++ containers?


(Note: This Q&A is an entry in Stack Overflow's C++ FAQ. Meta-discussion about the question itself should be posted on the Meta question that started all of this, not here.)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

终止放荡 2024-11-23 09:32:55

C++03 (来源:迭代器失效规则 ( C++03))


插入

序列容器

  • 向量:插入点之前的所有迭代器和引用不受影响,除非新容器大小大于先前的容量(在这种情况下,所有迭代器和引用都无效)[23.2.4.3/1]
  • deque:所有迭代器和引用都无效,除非插入的成员位于末尾(前面或后面)双端队列的(在这种情况下,所有迭代器都无效,但对元素的引用不受影响)[23.2.1.3/1]
  • list:所有迭代器和引用不受影响[23.2.2.3/1]

关联容器

  • [multi]{set,map}:所有迭代器和引用不受影响 [23.1.2/8]

容器适配器< /em>

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

擦除

序列容器

  • 向量:擦除点之后的每个迭代器和引用都无效[23.2.4.3/3]
  • 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]
  • 列表:按照插入/擦除[23.2.2.2/1]

注释1

除非另有说明(或者
显式或通过定义函数
就其他功能而言),调用
容器成员函数或传递
一个容器作为 a 的参数
库函数不得无效
迭代器
或更改其值,
该容器内的对象。
[23.1/11]

注 2

C++2003 中尚不清楚“end”迭代器是否受以上规则;无论如何,你应该假设它们是(因为实践中就是这种情况)。

注3:

指针失效的规则与引用失效的规则相同。

C++03 (Source: Iterator Invalidation Rules (C++03))


Insertion

Sequence containers

  • vector: all iterators and references before the point of insertion are unaffected, unless the new container size is greater than the previous capacity (in which case all iterators and references are invalidated) [23.2.4.3/1]
  • deque: all iterators and references are invalidated, unless the inserted member is at an end (front or back) of the deque (in which case all iterators are invalidated, but references to elements are unaffected) [23.2.1.3/1]
  • list: all iterators and references unaffected [23.2.2.3/1]

Associative containers

  • [multi]{set,map}: all iterators and references unaffected [23.1.2/8]

Container adaptors

  • stack: inherited from underlying container
  • queue: inherited from underlying container
  • priority_queue: inherited from underlying container

Erasure

Sequence containers

  • vector: every iterator and reference after the point of erase is invalidated [23.2.4.3/3]
  • deque: all iterators and references are invalidated, unless the erased members are at an end (front or back) of the deque (in which case only iterators and references to the erased members are invalidated) [23.2.1.3/4]
  • list: only the iterators and references to the erased element is invalidated [23.2.2.3/3]

Associative containers

  • [multi]{set,map}: only iterators and references to the erased elements are invalidated [23.1.2/8]

Container adaptors

  • stack: inherited from underlying container
  • queue: inherited from underlying container
  • priority_queue: inherited from underlying container

Resizing

  • vector: as per insert/erase [23.2.4.2/6]
  • deque: as per insert/erase [23.2.1.2/1]
  • list: as per insert/erase [23.2.2.2/1]

Note 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]

Note 2

It's not clear in C++2003 whether "end" iterators are subject to the above rules; you should assume, anyway, that they are (as this is the case in practice).

Note 3

The rules for invalidation of pointers are the sames as the rules for invalidation of references.

や三分注定 2024-11-23 09:32:55

C++11(来源:迭代器失效规则 (C++0x))


插入

序列容器

  • 向量:插入点之前的所有迭代器和引用不受影响,除非新容器size 大于先前的容量(在这种情况下,所有迭代器和引用都无效) [23.3.6.5/1]
  • deque:所有迭代器和引用都无效,除非插入的成员位于末尾(双端队列的前面或后面)(在这种情况下,所有迭代器都无效,但对元素的引用不受影响)[23.3.3.4/1]
  • list:所有迭代器和引用不受影响[23.3.5.4/1]
  • forward_list:所有迭代器和引用不受影响(适用于insert_after [23.3.4.5/1]
  • array(n/a)

关联容器

  • [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 :从底层容器继承

擦除

序列容器

  • 向量:擦除点或擦除点之后的每个迭代器和引用都无效[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]
  • 数组(n/a)

关联容器

  • [multi]{set,map}:只有迭代器和对已擦除元素的引用无效[23.2.4/9]

无序关联容器

  • unordered_[multi]{set,map}:只有迭代器和对已擦除元素的引用无效[23.2.5/13]

容器适配器

  • 堆栈:从底层容器继承
  • queue:从底层容器继承
  • priority_queue:从底层容器继承

调整

  • vector大小:根据插入/擦除[23.3.6.5/12]
  • deque:按照插入/擦除 [23.3.3.3/3]
  • list:按照插入/擦除 [23.3.5.3/1]
  • < code>forward_list:按照插入/擦除 [23.3.4.5/25]
  • array:(n/a)

注释 1

除非另有说明(或者
显式或通过定义函数
就其他功能而言),调用
容器成员函数或传递
一个容器作为 a 的参数
库函数不得无效
迭代器
或更改其值,
该容器内的对象。
[23.2.1/11]

注2

没有任何 swap() 函数会使任何
引用、指针或迭代器

提及的元素
容器正在交换。 [注:
end()迭代器
不引用任何
元素,因此它可能会失效
——尾注] [23.2.1/10]

Note 3

除了上述关于 swap() 的警告之外,尚不清楚“结束”迭代器是否受上面列出的每个容器规则的约束;无论如何,你应该假设它们是。

注 4

vector 和所有无序关联容器都支持 reserve(n),这保证至少在容器大小达到之前不会自动调整大小增长到n。应谨慎对待无序关联容器,因为未来的提案将允许指定最小负载因子,这将允许在足够的擦除后在插入上进行重新哈希 操作将容器大小减小到最小值以下;在擦除后,该保证应被视为可能无效。

C++11 (Source: Iterator Invalidation Rules (C++0x))


Insertion

Sequence containers

  • vector: all iterators and references before the point of insertion are unaffected, unless the new container size is greater than the previous capacity (in which case all iterators and references are invalidated) [23.3.6.5/1]
  • deque: all iterators and references are invalidated, unless the inserted member is at an end (front or back) of the deque (in which case all iterators are invalidated, but references to elements are unaffected) [23.3.3.4/1]
  • list: all iterators and references unaffected [23.3.5.4/1]
  • forward_list: all iterators and references unaffected (applies to insert_after) [23.3.4.5/1]
  • array: (n/a)

Associative containers

  • [multi]{set,map}: all iterators and references unaffected [23.2.4/9]

Unsorted associative containers

  • unordered_[multi]{set,map}: all iterators invalidated when rehashing occurs, but references unaffected [23.2.5/8]. Rehashing does not occur if the insertion does not cause the container's size to exceed z * B where z is the maximum load factor and B the current number of buckets. [23.2.5/14]

Container adaptors

  • stack: inherited from underlying container
  • queue: inherited from underlying container
  • priority_queue: inherited from underlying container

Erasure

Sequence containers

  • vector: every iterator and reference at or after the point of erase is invalidated [23.3.6.5/3]
  • deque: erasing the last element invalidates only iterators and references to the erased elements and the past-the-end iterator; erasing the first element invalidates only iterators and references to the erased elements; erasing any other elements invalidates all iterators and references (including the past-the-end iterator) [23.3.3.4/4]
  • list: only the iterators and references to the erased element is invalidated [23.3.5.4/3]
  • forward_list: only the iterators and references to the erased element is invalidated (applies to erase_after) [23.3.4.5/1]
  • array: (n/a)

Associative containers

  • [multi]{set,map}: only iterators and references to the erased elements are invalidated [23.2.4/9]

Unordered associative containers

  • unordered_[multi]{set,map}: only iterators and references to the erased elements are invalidated [23.2.5/13]

Container adaptors

  • stack: inherited from underlying container
  • queue: inherited from underlying container
  • priority_queue: inherited from underlying container

Resizing

  • vector: as per insert/erase [23.3.6.5/12]
  • deque: as per insert/erase [23.3.3.3/3]
  • list: as per insert/erase [23.3.5.3/1]
  • forward_list: as per insert/erase [23.3.4.5/25]
  • array: (n/a)

Note 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]

Note 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]

Note 3

Other than the above caveat regarding swap(), it's not clear whether "end" iterators are subject to the above listed per-container rules; you should assume, anyway, that they are.

Note 4

vector and all unordered associative containers support reserve(n) which guarantees that no automatic resizing will occur at least until the size of the container grows to n. Caution should be taken with unordered associative containers because a future proposal will allow the specification of a minimum load factor, which would allow rehashing to occur on insert after enough erase operations reduce the container size below the minimum; the guarantee should be considered potentially void after an erase.

流年里的时光 2024-11-23 09:32:55

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


插入

序列容器

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

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

  • list:不影响迭代器和引用的有效性。如果抛出异常,则不会产生任何影响。 [26.3.10.4/1].
    插入emplace_frontemplace_backemplacepush_frontpush_back 函数涵盖在该规则中。

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

  • array:< a href="https://en.cppreference.com/w/cpp/container/array#Iterator_invalidation" rel="noreferrer">通常,数组的迭代器永远不会失效在阵列的整个生命周期中。然而,应该注意的是,在交换过程中,迭代器将继续指向同一个数组元素,从而改变其值。

关联容器

  • 所有关联容器insertemplace 成员不应影响迭代器和对容器 [26.2.6/9]

无序关联容器

  • 所有无序关联容器:重新哈希无效迭代器,更改元素之间的顺序,并更改元素出现在哪些存储桶中,但不会使元素的指针或引用无效。 [26.2.7/9]
    insertemplace 成员不应影响对容器元素的引用的有效性,但可能会使容器的所有迭代器无效。 [26.2.7/14]
    如果 (N+n) <= z * B,则 insertemplace 成员不会影响迭代器的有效性,其中 N 是插入操作之前容器中的元素数量,n 是插入的元素数量,B 是容器的存储桶计数,< code>z 是集装箱的最大负载系数。 [26.2.7/15]

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

容器适配器

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

擦除

序列容器

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

  • deque:擦除 deque 最后一个元素的擦除操作仅使尾后迭代器以及所有迭代器和对已擦除元素的引用。擦除双端队列的第一个元素但不擦除最后一个元素的擦除操作只会使迭代器和对已擦除元素的引用无效。既不删除双端队列的第一个元素也不删除最后一个元素的擦除操作会使尾后迭代器以及对双端队列所有元素的所有迭代器和引用无效。
    [注:pop_frontpop_back是擦除操作。 ——尾注] [26.3.8.4/4]

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


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

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

  • 所有序列容器分配使所有引用、指针和
    引用容器元素的迭代器。对于vectordeque,也会使尾后迭代器无效。 (表 87 — 顺序容器要求)

关联容器

  • 所有关联容器erase 成员应仅使迭代器和对已擦除对象的引用无效元素[26.2.6/9]

  • 所有关联容器extract 成员仅使已删除元素的迭代器无效;指向已删除元素的指针和引用仍然有效[26.2.6/10]

容器适配器

  • 堆栈:从底层容器继承
  • 队列:从底层继承容器
  • priority_queue:继承自底层容器

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

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

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

作为上述要求的示例:

  • transform 算法:opbinary_op 函数不得使迭代器或子范围无效,或修改范围 [28.6.4/1]

    中的元素

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

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

等等...

C++17 (All references are from the final working draft of CPP17 - n4659)


Insertion

Sequence Containers

  • vector: The functions insert, emplace_back, emplace, push_back cause reallocation if the new size is greater than the old capacity. Reallocation invalidates all the references, pointers, and iterators referring to the elements in the sequence. If no reallocation
    happens, all the iterators and references before the insertion point remain valid. [26.3.11.5/1]
    With respect to the reserve function, reallocation invalidates all the references, pointers, and iterators referring to the elements in the sequence. No reallocation shall take 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(). [26.3.11.3/6]

  • deque: An insertion in the middle of the deque invalidates all the iterators and references to elements of the deque. An insertion at either end of the deque invalidates all the iterators to the deque, but has no effect on the validity of references to elements of the deque. [26.3.8.4/1]

  • list: Does not affect the validity of iterators and references. If an exception is thrown there are no effects. [26.3.10.4/1].
    The insert, emplace_front, emplace_back, emplace, push_front, push_back functions are covered under this rule.

  • forward_list: None of the overloads of insert_after shall affect the validity of iterators and references [26.3.9.5/1]

  • array: As a rule, iterators to an array are never invalidated throughout the lifetime of the array. One should take note, however, that during swap, the iterator will continue to point to the same array element, and will thus change its value.

Associative Containers

  • All Associative Containers: The insert and emplace members shall not affect the validity of iterators and references to the container [26.2.6/9]

Unordered Associative Containers

  • All Unordered Associative Containers: Rehashing invalidates iterators, changes ordering between elements, and changes which buckets elements appear in, but does not invalidate pointers or references to elements. [26.2.7/9]
    The insert and emplace members shall not affect the validity of references to container elements, but may invalidate all iterators to the container. [26.2.7/14]
    The insert and emplace members shall not affect the validity of iterators if (N+n) <= z * B, where N is the number of elements in the container prior to the insert operation, n is the number of elements inserted, B is the container’s bucket count, and z is the container’s maximum load factor. [26.2.7/15]

  • All Unordered Associative Containers: In case of a merge operation (e.g., a.merge(a2)), iterators referring to the transferred elements and all iterators referring to a will be invalidated, but iterators to elements remaining in a2 will remain valid. (Table 91 — Unordered associative container requirements)

Container Adaptors

  • stack: inherited from underlying container
  • queue: inherited from underlying container
  • priority_queue: inherited from underlying container

Erasure

Sequence Containers

  • vector: The functions erase and pop_back invalidate iterators and references at or after the point of the erase. [26.3.11.5/3]

  • deque: An erase operation that erases the last element of a deque invalidates only the past-the-end iterator and all iterators and references to the erased elements. An erase operation that erases the first element of a deque but not the last element invalidates only iterators and references to the erased elements. An erase operation that erases neither the first element nor the last element of a deque invalidates the past-the-end iterator and all iterators and references to all the elements of the deque.
    [ Note: pop_front and pop_back are erase operations. —end note ] [26.3.8.4/4]

  • list: Invalidates only the iterators and references to the erased elements. [26.3.10.4/3]. This applies to erase, pop_front, pop_back, clear functions.
    remove and remove_if member functions: Erases all the elements in the list referred by a list iterator i for which the following conditions hold: *i == value, pred(*i) != false. Invalidates only the iterators and references to the erased elements [26.3.10.5/15].
    unique member function - Erases all but the first element from every consecutive group of equal elements referred to by the iterator i in the range [first + 1, last) for which *i == *(i-1) (for the version of unique with no arguments) or pred(*i, *(i - 1)) (for the version of unique with a predicate argument) holds. Invalidates only the iterators and references to the erased elements. [26.3.10.5/19]

  • forward_list: erase_after shall invalidate only iterators and references to the erased elements. [26.3.9.5/1].
    remove and remove_if member functions - Erases all the elements in the list referred by a list iterator i for which the following conditions hold: *i == value (for remove()), pred(*i) is true (for remove_if()). Invalidates only the iterators and references to the erased elements. [26.3.9.6/12].
    unique member function - Erases all but the first element from every consecutive group of equal elements referred to by the iterator i in the range [first + 1, last) for which *i == *(i-1) (for the version with no arguments) or pred(*i, *(i - 1)) (for the version with a predicate argument) holds. Invalidates only the iterators and references to the erased elements. [26.3.9.6/16]

  • All Sequence Containers: clear invalidates all references, pointers, and iterators referring to the elements of a and may invalidate the past-the-end iterator (Table 87 — Sequence container requirements). But for forward_list, clear does not invalidate past-the-end iterators. [26.3.9.5/32]

  • All Sequence Containers: assign invalidates all references, pointers and
    iterators referring to the elements of the container. For vector and deque, also invalidates the past-the-end iterator. (Table 87 — Sequence container requirements)

Associative Containers

  • All Associative Containers: The erase members shall invalidate only iterators and references to the erased elements [26.2.6/9]

  • All Associative Containers: The extract members invalidate only iterators to the removed element; pointers and references to the removed element remain valid [26.2.6/10]

Container Adaptors

  • stack: inherited from underlying container
  • queue: inherited from underlying container
  • priority_queue: inherited from underlying container

General container requirements relating to iterator invalidation:

  • 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. [26.2.1/12]

  • 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 ] [26.2.1/(11.6)]

As examples of the above requirements:

  • transform algorithm: The op and binary_op functions shall not invalidate iterators or subranges, or modify elements in the ranges [28.6.4/1]

  • accumulate algorithm: In the range [first, last], binary_op shall neither modify elements nor invalidate iterators or subranges [29.8.2/1]

  • reduce algorithm: binary_op shall neither invalidate iterators or subranges, nor modify elements in the range [first, last]. [29.8.3/5]

and so on...

放飞的风筝 2024-11-23 09:32:55

可能值得补充的是,任何类型的插入迭代器(std::back_insert_iterator、std::front_insert_iterator、std::insert_iterator)都是只要通过此迭代器执行所有插入并且没有其他独立的迭代器无效事件发生,就保证保持有效。

例如,当您使用 std::insert_iteratorstd::vector 执行一系列插入操作时,这些插入很可能会触发向量重新分配,这将使所有“指向”该向量的迭代器无效。然而,所涉及的插入迭代器保证保持有效,即您可以安全地继续插入序列。根本无需担心触发向量重新分配。

同样,这仅适用于通过插入迭代器本身执行的插入。如果迭代器无效事件是由容器上的某些独立操作触发的,则根据一般规则,插入迭代器也会变得无效。

例如,

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();

即使向量“决定”在此过程中间的某个位置重新分配,此代码也能保证对向量执行有效的插入序列。迭代器 it 显然会变得无效,但 it_ins 将继续保持有效。

It is probably worth adding that an insert iterator of any kind (std::back_insert_iterator, std::front_insert_iterator, std::insert_iterator) is guaranteed to remain valid as long as all insertions are performed through this iterator and no other independent iterator-invalidating event occurs.

For example, when you are performing a series of insertion operations into a std::vector by using std::insert_iterator it is quite possible that these insertions will trigger vector reallocation, which will invalidate all iterators that "point" into that vector. However, the insert iterator in question is guaranteed to remain valid, i.e. you can safely continue the sequence of insertions. There's no need to worry about triggering vector reallocation at all.

This, again, applies only to insertions performed through the insert iterator itself. If iterator-invalidating event is triggered by some independent action on the container, then the insert iterator becomes invalidated as well in accordance with the general rules.

For example, this code

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();

is guaranteed to perform a valid sequence of insertions into the vector, even if the vector "decides" to reallocate somewhere in the middle of this process. Iterator it will obviously become invalid, but it_ins will continue to remain valid.

傲娇萝莉攻 2024-11-23 09:32:55

这是来自 cppreference.com 的一个很好的汇总表:

在此处输入图像描述

这里,插入是指向容器添加一个或多个元素的任何方法,而擦除是指从容器中删除一个或多个元素的任何方法。

Here is a nice summary table from cppreference.com:

enter image description here

Here, insertion refers to any method which adds one or more elements to the container and erasure refers to any method which removes one or more elements from the container.

同尘 2024-11-23 09:32:55

由于这个问题吸引了如此多的选票,并且有点成为常见问题解答,我想最好写一个单独的答案来提及 C++03 和 C++11 之间关于 std:: 影响的一个显着差异。 vector 对迭代器和引用相对于 reserve()capacity() 有效性的插入操作,这是最多支持的答案未能注意到的。

C++ 03:

重新分配会使所有引用、指针和迭代器失效
引用序列中的元素。保证不会
重新分配发生在调用后发生的插入期间
Reserve() 直到插入的大小达到
向量大于最近调用中指定的大小
保留()

C++11:

重新分配会使所有引用、指针和迭代器失效
引用序列中的元素。保证不会
重新分配发生在调用后发生的插入期间
Reserve() 直到插入的大小达到
向量大于capacity()的值

因此,在 C++03 中,它不是另一个答案中提到的“除非新容器大小大于以前的容量(在这种情况下所有迭代器和引用都无效)”,而是,它应该“大于最近一次调用reserve()时指定的大小”。这是 C++03 与 C++11 的不同之处之一。在 C++03 中,一旦 insert() 导致向量的大小达到先前 reserve() 调用中指定的值(该值很可能小于当前的capacity(),因为reserve()可能会导致比要求的更大的capacity()),任何后续的insert( ) 可能会导致重新分配并使所有迭代器和引用。在 C++11 中,这种情况不会发生,您始终可以相信 capacity() 可以确定地知道,在大小超过 capacity()< 之前不会进行下一次重新分配。 /代码>。

总之,如果您正在使用 C++03 向量,并且希望确保执行插入时不会发生重新分配,那么它就是您之前传递给 reserve() 您应该检查大小,而不是调用 capacity() 的返回值,否则您可能会对“过早”重新分配感到惊讶。

Since this question draws so many votes and kind of becomes an FAQ, I guess it would be better to write a separate answer to mention one significant difference between C++03 and C++11 regarding the impact of std::vector's insertion operation on the validity of iterators and references with respect to reserve() and capacity(), which the most upvoted answer failed to notice.

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().

So in C++03, it is not "unless the new container size is greater than the previous capacity (in which case all iterators and references are invalidated)" as mentioned in the other answer, instead, it should be "greater than the size specified in the most recent call to reserve()". This is one thing that C++03 differs from C++11. In C++03, once an insert() causes the size of the vector to reach the value specified in the previous reserve() call (which could well be smaller than the current capacity() since a reserve() could result a bigger capacity() than asked for), any subsequent insert() could cause reallocation and invalidate all the iterators and references. In C++11, this won't happen and you can always trust capacity() to know with certainty that the next reallocation won't take place before the size overpasses capacity().

In conclusion, if you are working with a C++03 vector and you want to make sure a reallocation won't happen when you perform insertion, it's the value of the argument you previously passed to reserve() that you should check the size against, not the return value of a call to capacity(), otherwise you may get yourself surprised at a "premature" reallocation.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文