Reputation: 55
Following lines of C++ code gives runtime error but if erase operation mymap.erase(v)
is removed it works:
map<int,int> mymap = {{1,0},{2,1},{9,2},{10,3},{11,4}};
for(auto it=mymap.rbegin();it!=mymap.rend();){
int v=it->first;
++it;
mymap.erase(v);
}
Here iterator it
is changed before deleting its value v
, so iterator it
should remain unaffected I believe.
Upvotes: 5
Views: 397
Reputation: 122595
Indeed, std::map::erase
:
References and iterators to the erased elements are invalidated. Other references and iterators are not affected.
For a reverse iterator r constructed from an iterator i, the relationship
&*r == &*(i-1)
is always true (as long as r is dereferenceable); thus a reverse iterator constructed from a one-past-the-end iterator dereferences to the last element in a sequence.
Perhaps it gets more clear when you look at the image on the cppreference page.
The crucial part is "Reverse iterator stores an iterator to the next element than the one it actually refers to".
As a consequence (small modification to your code)
auto& element = *it; // fails in the next iteration, because...
int v = element.first;
++it; // now it stores an iterator to element
mymap.erase(v); // iterators to element are invalidated
You are erasing the element that is used by it
in the next iteration.
Upvotes: 5
Reputation: 596673
When you are calling erase(v)
, you are invalidating the base iterator
that the next reverse_iterator
(from ++it
) is using. So you need to create a new reverse_iterator
from the base iterator
that precedes the erased value.
Also, rather than erasing the value that the reverse_iterator
is referring to, you should erase the base iterator
instead, since you already know which element you want to erase. There is no need to make the map
go hunting for the value again.
This works for me:
map<int,int> mymap = {{1,0},{2,1},{9,2},{10,3},{11,4}};
for(auto it = mymap.rbegin(); it != mymap.rend(); ){
auto v = --(it.base());
v = mymap.erase(v);
it = map<int,int>::reverse_iterator(v);
}
On the other hand, this loop is essentially just erase()
'ing all elements from mymap
, so a better option is to use mymap.clear()
instead.
Upvotes: 10