Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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++; 
}
like image 491
Ram Avatar asked Mar 13 '23 04:03

Ram


1 Answers

  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()));
}
like image 193
songyuanyao Avatar answered Mar 14 '23 18:03

songyuanyao