Problem with std::map::iterator after calling erase()

后端 未结 5 743
無奈伤痛
無奈伤痛 2020-12-01 07:01
// erasing from map
#include 
#include 
using namespace std;

int main ()
{
  map mymap;
  map::iterator i         


        
相关标签:
5条回答
  • 2020-12-01 07:24

    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.

    0 讨论(0)
  • 2020-12-01 07:26

    it is no longer valid after mymap.erase(it). This means, it can do whatever it wants.

    0 讨论(0)
  • 2020-12-01 07:27

    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.

    0 讨论(0)
  • 2020-12-01 07:29

    "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.

    0 讨论(0)
  • 2020-12-01 07:35

    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;
        }
    }
    
    0 讨论(0)
提交回复
热议问题