Susliks Susliks - 4 days ago 4
C++ Question

What happens at the end with the iterator when a list element is erased?

I wrote this simple test program. But i can't understand what happens here. Because there is a strange thing in the output:

std::list<std::pair<double,double>> l;
l.push_back({0.3,0.9});
l.push_back({-0.3,0.5});
l.push_back({0.3,0.7});
l.push_back({1.2,1.83});


for(auto it=l.begin(); it!=l.end(); ++it){
double lx= it->first + 0.01;
double ly= it->second + 0.01;

it->first = lx;
it->second = ly;

if(lx < 0.0 || lx > 1.0 || ly < 0.0 || ly > 1.0){
it = l.erase(it);
}


If i print the list, i get:

0.32, 0.92
0.31, 0.71


Why does the iterator goes back to the first element (twice +0.1) ?

Answer
it=list.erase(it);

This erases the element at it. It then returns the iterator location after the erased element was.

When your for loop finishes an iteration, it advances it, via ++ then checks if it equals end().

So your loop both skips the element after each one erased. Not good. And if it erases the last element it proceeds to advsnce the end iterator, which is illegal.

Remove ++it from the for loop header. At the bottom of the loop, either advance it or erase at it, not both nor neither.

The strange printing behaviour is due to UB. You increment data at location 0. You increment data at location 1, then delete it. You skip location 2. You increment data at location 3, then delete it. You advance past the end iterator (undefined behaviour). Then random stuff happens that just happens to increment data location 0 and 2 again. As a guess, ++ on the end iterator happens to loop back to the first element in your particular case (this is not guaranteed at all, but with UB anything can happen). The second loop then runs as normal, incrementing the data at the two elements and deleting nothing.

Comments