0

I have a for loop with a map like this.

std::map<int,std::string> mymap = {{1,"a"},{2,"b"},{3,"c"}};

for(std::map<int,std::string>::iterator it = mymap.begin(); it!=mymap.end(); ++it)
{
    if(it->first==3)
    {
        mymap.erase(it);
    }
}

std::cout << mymap.rbegin()->second << std::endl;

The output is "b" as expected. The question is: Can this lead to an infinite loop (or a crash) somehow? I mean after

erase(it)

the iterator it is invalid. If the erased item was not the last one, it should be ok, because "it" is incremented after the erasion and when the condition is evaluated it points to mymap.end() at max. But if I erase the last one, after erasion mymap.end() should be after the last remaining item, and then it is incremented anyways. Can't it somehow run out of range? Shouldn't I use something like

for(std::map<int,std::string>::iterator it = mymap.begin(); it!=mymap.end(); ++it)
{
    std::map<int,std::string>::const_iterator tempit = it;
    const bool lastItemErased = ++tempit == mymap.end();

    if(it->first==3)
    {
        mymap.erase(it);
    }

    if(lastItemErased) break;
}

to be safe?

note: both of the above runs and behaves as expected if I try to erase the element with key 3 and 2. I don't see how is this possible and why doesn't it crash. How can I increment an invalid iterator?

update: It has to work with c++03. I initialized the map like this, to post the question more easily.

TmsKtel
  • 361
  • 3
  • 11
  • If the iterator becomes invalid then using it is, by definition, not safe. It is "undefined" behavious so anything can happen. – Galik Sep 26 '15 at 09:58
  • For safe usage, se the example in the docs here: http://en.cppreference.com/w/cpp/container/map/erase – Galik Sep 26 '15 at 10:01
  • Using a rbegin after erase , will get the last element from map , so why do you think it should crash ? If you are using a forward iterator than you must do it the way as pointed by answers in link to question to which your question is marked duplicate . – Invictus Sep 26 '15 at 10:19

1 Answers1

1

Edit: Only works for C++11 and above.

std::map::erase returns a new valid iterator object (that is the element following the removed one, which is mymap.end() in your example). You should use that return value:

for(std::map<int,std::string>::iterator it = mymap.begin(); it!=mymap.end();)
{
    if(it->first==3)
    {
        it = mymap.erase(it);
    }
    else
    {
        ++it;
    }
}

See http://en.cppreference.com/w/cpp/container/map/erase for reference.

Lukas W
  • 305
  • 1
  • 9