Search code examples
c++iteratordequeerase

Segmentation fault when erasing elements while iterating std::deque


Why does the following code crash? And what should I do when I am iterating via reverse iterator. How do I erase individual elements then?

deque q;
q.push_back(4);
q.push_back(41);
q.push_back(14);

for (auto it = q.begin(); it != q.end();) {
    auto current = it;
    q.erase(current);
    it++; 
}

Solution

    1. Why does the following code crash ? How do I erase individual elements then ?

    std::deque::erase invalidates iterators.

    All iterators and references are invalidated, unless the erased elements are at the end or the beginning of the container, in which case only the iterators and references to the erased elements are invalidated.

    The past-the-end iterator is also invalidated unless the erased elements are at the beginning of the container and the last element is not erased.

    In your code, the iterators to the element to be erased (i.e. it and current) will become invalid after q.erase(current), then it++ will lead to UB.

    You could make use of the return value of std::deque::erase

    Iterator following the last removed element. If the iterator pos refers to the last element, the end() iterator is returned.

    for (auto it = q.begin(); it!=q.end(); )
    {
        it = q.erase(it);
    }
    
    1. And what should I do if I am iterating via reverse iterator.

    Because std::deque::erase doesn't accept reverse_iterator as parameters, you need to use base() to convert it to normal iterator (pay attention to the position conversion). Such as

    for (auto it = q.rbegin(); it!=q.rend(); )
    {
        it = std::make_reverse_iterator(q.erase((++it).base()));
    }