迭代时从 std::list 中删除

Removing from std::list while iterating

本文关键字:list 删除 std 迭代      更新时间:2023-10-16

我有以下代码:

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 语句的下一次迭代出现分段错误。

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

如果删除的项目是列表中的最后一项,则 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
    }
}

正如现在所写的那样,即使在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;
}