【问题标题】:Do STL iterators guarantee validity after collection was changed?STL 迭代器是否保证集合更改后的有效性?
【发布时间】:2011-03-20 18:53:03
【问题描述】:

假设我有某种集合,并且我在它的开头获得了一个迭代器。现在假设我修改了集合。无论集合或迭代器的类型如何,我仍然可以安全地使用迭代器吗?

为避免混淆,以下是我所说的操作顺序:

  1. 获取集合的迭代器。
  2. 修改集合(显然 不是其中的元素,而是集合本身)。
  3. 使用第1步得到的迭代器,按照STL标准还有效吗?!

【问题讨论】:

  • 感谢大家的快速回复。

标签: c++ stl iterator containers


【解决方案1】:

不,迭代器只有在迭代容器不变时才有效。如果集合被修改,则需要重新获取迭代器。

【讨论】:

  • 严格来说这不是真的(示例列表不遵循这些规则)。
  • 这个问题被问到“不管集合(容器)的类型”。
  • 不管是什么问题,您的回答中的陈述都具有误导性,因为它在某些情况下是正确的,而在(许多)其他情况下是错误的。
【解决方案2】:

取决于容器。例如如果是vector,修改容器后所有的迭代器都会失效。但是,如果是list,则与修改位置无关的迭代器将保持有效。

  • 向量的迭代器在其内存被重新分配时失效。此外,在向量中间插入或删除元素会使指向插入或删除点之后元素的所有迭代器无效。因此,如果您使用reserve() 预分配向量将使用的尽可能多的内存,并且所有插入和删除都在向量的末尾,则可以防止向量的迭代器失效。 [1]

  • deque 的迭代器失效语义如下。 Insert(包括push_frontpush_back)使所有引用deque 的迭代器无效。在deque 中间的Erase 使所有引用deque 的迭代器无效。 Erasedeque(包括 pop_frontpop_back)的开头或结尾处,仅当迭代器指向已擦除的元素时才会使其无效。 [2]

  • Lists 具有重要的属性,即插入和拼接不会使列表元素的迭代器失效,即使删除也会使指向被删除元素的迭代器失效。 [3]

  • Map 具有重要的属性,即向map 插入新元素不会使指向现有元素的迭代器无效。从映射中擦除元素也不会使任何迭代器失效,当然,除了实际指向被擦除元素的迭代器。 [4]setmultisetmultimap 相同)

【讨论】:

  • 但是,vector::insert(单个元素)和vector::erase 返回一个新的有效迭代器。
  • 肯尼:根据标准,你说的是真的还是因为stl通常是这样实现的?你能修改你的答案,让它也解释一下吗?谢谢。
  • @yossi1981:这是由标准定义的。迭代器失效的条件在标准中有非常明确的定义。
【解决方案3】:

这取决于相关的集合。例如,修改std::vector(例如,在某处添加元素)可以使该向量中的所有迭代器无效。相比之下,使用std::list,当您将另一个元素添加到列表中时,迭代器仍然有效。在某些情况下,规则甚至更复杂(例如,如果内存服务,使用std::deque,添加到开头或结尾会使现有迭代器有效,但在其他任何地方添加会使它们无效 - 但我的记忆力很差,以至于你应该先检查一下)。

【讨论】:

  • 如果你删除一个列表元素怎么办?如果它是迭代器指向的元素呢?
  • 擦除迭代器引用的元素会使该迭代器无效。擦除任何其他元素不会。
  • 也就是说,如果你修改列表,在某些情况下它会使迭代器失效(指向被擦除的元素),所以迭代器的有效性不能保证——对吗?
猜你喜欢
  • 1970-01-01
  • 2012-01-21
  • 1970-01-01
  • 1970-01-01
  • 2011-02-14
  • 2021-09-24
  • 1970-01-01
  • 1970-01-01
  • 2014-10-23
相关资源
最近更新 更多