Problem with std::map::iterator after calling erase()
// erasing from map
#include <iostream>
#include <map>
using namespace std;
int main ()
{
map<char,int> mymap;
map<char,int>::iterator it(mymap.begin());
// insert some values:
mymap['a']=10;
mymap['b']=20;
mymap['c']=30;
mymap['d']=40;
mymap['e']=50;
mymap['f']=60;
it=mymap.find('a');
mymap.erase (it); // erasing by iterator
// show content:
for (; it != mymap.end(); it++ )
cout << (*it).first << " => " << (*it).second << endl;
return 0;
}
Why does this give an output like
a => 10
b => 20
c => 30
d => 40
e => 50
f => 60
shouldn't "a =&g开发者_如何转开发t; 10"
be deleted anyways, but if I declare it = mymap.begin()
in the for loop, everything is perfect. why?
program adapted from : http://www.cplusplus.com/reference/stl/map/erase/
Erasing an element of a map
invalidates iterators pointing to that element (after all that element has been deleted). You shouldn't reuse that iterator.
Since C++11 erase()
returns a new iterator pointing to the next element, which can be used to continue iterating:
it = mymap.begin();
while (it != mymap.end()) {
if (something)
it = mymap.erase(it);
else
it++;
}
Before C++11 you would have to manually advance the iterator to the next element before the deletion takes place, for example like this:
mymap.erase(it++);
This works because the post-increment side-effect of it++
happens before erase()
deletes the element. Since this is maybe not immediately obvious, the C++11 variant above should be preferred.
Calling erase()
invalidates the iterator. In this case, what's happening is the iterator points to the residual value left behind in memory (but don't rely on this undefined behaviour!). Reset the iterator with it=mymap.begin()
before the loop for the desired results.
http://codepad.org/zVFRtoV5
This answer shows how to erase elements while iterating over an std::map
:
for(map<T, S*>::iterator it = T2pS.begin(); it != T2pS.end(); T2pS.erase(it++)) {
// wilhelmtell in the comments is right: no need to check for NULL.
// delete of a NULL pointer is a no-op.
if(it->second != NULL) {
delete it->second;
it->second = NULL;
}
}
it
is no longer valid after mymap.erase(it)
. This means, it can do whatever it wants.
This has to do with how the map
is implemented. Let's say it's a tree of some sort, like:
class map_node {
char key;
int value;
map_node* next;
...
};
When you erase()
the iterator, you remove the node from the tree and deallocate its space. But until that memory location is overwritten, the node's contents are still in memory. That's why you can get not only the value, but also the next element in the tree. Thus, your result is completely expected.
"it" still points at the same location, erase does not update the iterator by itself, you have to do it, by resetting the iterator. In effect, "it" points to the old location which has been erased from the vector but still contains the old data.
精彩评论