【问题标题】:Removing from std::list while iterating迭代时从 std::list 中删除
【发布时间】:2016-07-15 06:43:30
【问题描述】:

我有以下代码:

bool resetTypeBit = true;
for (auto it = eventsList.begin(); it != eventsList.end(); ++it) {
    CreatureEvent* curEvent = *it;
    if (curEvent == event) {
        it = eventsList.erase(it);
    } else if (curEvent->getEventType() == type) {
        resetTypeBit = false;
    }
}

所以我有以下场景:eventList 包含 01 项,然后,一旦for 语句第一次通过并遇到it = eventsList.erase(it); 行,it 变量就变为无效,在for 语句的下一次迭代中导致分段错误。

任何可能导致问题的线索?

【问题讨论】:

    标签: c++ list c++11 stl


    【解决方案1】:

    正如现在所写的那样,即使在erase 分支中,您也在递增迭代器,这意味着您总是在删除一个元素之后跳过该元素。如果最后一个元素恰好是要删除的元素,这既不正确,也会导致严重问题。要修复,如果您已经修复it,则不必增加,方法是将其设置为已删除元素之后的元素。

    bool resetTypeBit = true;
    for (auto it = eventsList.begin(); it != eventsList.end(); ) {
        CreatureEvent* curEvent = *it;
        if (curEvent == event) {
            it = eventsList.erase(it);
            continue;
        } else if (curEvent->getEventType() == type) {
            resetTypeBit = false;
        }
        ++it;
    }
    

    【讨论】:

      【解决方案2】:

      如果您删除的项目是列表中的最后一项,erase 方法将返回 end()。然后,您的 for 循环将尝试增加该迭代器,这会导致未定义的行为。

      您还没有遇到的另一个问题是,如果您删除的项目不是列表中的最后一个项目,您最终会跳过下一个项目(因为迭代器递增超过一个erase 返回)。您可以将erase 视为一个增量操作,它恰好首先擦除该项目。

      解决方案是稍微重构循环,将增量移到末尾(并且仅在未调用 erase 时):

      bool resetTypeBit = true;
      for (auto it = eventsList.begin(); it != eventsList.end(); ) {
          CreatureEvent* curEvent = *it;
          if (curEvent == event) {
              it = eventsList.erase(it);
          }
          else {
              if (curEvent->getEventType() == type) {
                  resetTypeBit = false;
              }
              ++it; // move the increment to here
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2013-04-22
        • 2010-10-10
        • 2011-07-13
        • 1970-01-01
        • 2011-02-21
        • 2019-03-10
        相关资源
        最近更新 更多