简体   繁体   中英

Removing from std::list while iterating

I have the following code:

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;
    }
}

So I have the following scenario: eventList contains 01 item, and then, as soon as the for statement goes through for the first time and meet the it = eventsList.erase(it); line, the it variable becomes invalid, causing a segmentation fault on the next iteration of the for statement.

Any clues of what could be causing the problem?

If the item you remove is the last item in the list, the erase method will return end() . Your for loop will then try to increment that iterator, which results in undefined behaviour.

Another problem which you haven't come across yet is that, if the item you remove isn't the last item in the list, you'll end up skipping over the following item (because the iterator is incremented past the one that erase returns). You can think of erase as an increment operation that just happens to erase the item first.

The solution is to refactor the loop slightly, to move the increment to the end (and only if erase wasn't called):

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
    }
}

As it is written now, you are incrementing the iterator even in the erase branch, which means that you are always skipping the element just after an erased one. This is both incorrect and results in serious problems if the last element happens to be one to delete. To fix, you have to not increment if you already fix it by setting it to the element following the deleted one.

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;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM