【问题标题】:Validity of iterator pointing to erased item指向已擦除项目的迭代器的有效性
【发布时间】:2011-03-21 14:53:35
【问题描述】:

that page,据说:

这会使所有迭代器和 对位置后元素的引用 或首先。

这是否意味着positionfirst 迭代器在擦除后有效?

(显然,我问这个是因为我想在 for_each 循环期间删除向量中的某些项目。)

谢谢。

【问题讨论】:

    标签: c++ stl iterator erase


    【解决方案1】:

    根据http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#414 positonfirst 应该被认为是无效的 - 标准中的措辞不清楚,但因为迭代器和引用在一个句子中提到,并且对已擦除元素的引用没有意义,这是“理所当然的”,擦除指向被擦除元素的迭代器无效。我会避免依赖已擦除的迭代器是否有效 - 当您从具有一个元素的向量中擦除 begin() 时,我不会想当然地认为迭代器突然等于 end()

    【讨论】:

    • " 该标准明确指出:“在擦除点之后使所有迭代器和引用无效。”这已作为缺陷提出。C++0x 的 N3242 草案将其更改为:“在擦除点或之后使迭代器和引用无效。” – Jerry Coffin。
    • @Jerry Coffin 所以我明白了。然而,这显然是一个缺陷,因为不使迭代器无效的定义意味着它指向与之前相同的元素。如果元素已被删除,这是不可能的。
    【解决方案2】:

    通常,如果您尝试在循环中从vector 中删除多个项目,使用remove_if 会比在每个项目上使用erase 提供更好的性能。考虑这个而不是迭代擦除。

    但是,要回答您的问题,是的,它们是有效的,但在再次测试 end 之前要小心递增迭代器,因为擦除可能会使您的迭代器现在等于 end。编辑:@Erik 的回答表明它实际上可能无效,但措辞不清楚。

    【讨论】:

    • 性能(还)不是问题,而且我对 stl 不够熟悉,无法用算法编写漂亮的代码。
    【解决方案3】:

    是的。但它们不会像在erase() 之前那样引用相同的元素,因为该元素将被删除!

    【讨论】:

      【解决方案4】:

      如果您在迭代时进行擦除,请考虑以下语法:

      vector<int> items = ...;
      
      for(vector<int>::iterator it = items.begin() ; it != items.end() ; /*inline*/)
      {
         if(/* should erase*/)
            it = items.erase(it);
         else
            ++it;
      }
      

      这是因为erase() 返回一个迭代器,指向当前元素之后的下一个元素。所以,如果你擦除,它会“增加”,否则,你会像往常一样增加它。正如其他人所指出的那样,这不是很有效(因为当前元素之后的所有元素都被向前复制),并且有更好的方法。例如,正如 Mark B 所提到的,使用remove_if 可能会更好。

      【讨论】:

      • 谢谢你的提示,我会这样做的。
      【解决方案5】:

      这就是它所说的,但它是错误的。根据标准, 它们是无效的(这是有道理的,因为要保持有效, 他们必须指向一个不再存在的元素。

      【讨论】:

      • 其实,没有。该标准特别指出:“使所有迭代器和引用在擦除点之后 无效。”这已作为缺陷提出。 C++0x 的 N3242 草案将其更改为:“使迭代器和引用在擦除点或之后无效。”
      • 非常有用的评论 Jerry Coffin。
      猜你喜欢
      • 2014-10-23
      • 2021-01-02
      • 1970-01-01
      • 1970-01-01
      • 2016-03-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多