0

I'm trying to test if "find" is safe in std:map so I've erased an element after I use "find" to test it but the iterator to the element is still valid. Even if I use find again it finds the erased element again.

According to documentation:

Iterators, pointers and references referring to elements removed by the function are invalidated. All other iterators, pointers and references keep their validity.

  • Why does the second iterator auto it_2 = numeros.find("uno"); finds the element if it was erased?

  • Why does std::cout << it->first << " : " << it->second << std::endl; after "erase" prints the element? It means find is safe when the element is removed from the map?

This is my example.

#include <iostream>
#include <map>

int main(int argc, char *argv[])
{
    std::map<std::string,unsigned int> numeros = { {"uno",1}, {"dos",2}, {"tres",3}};

    auto it = numeros.find("uno");
    std::cout << it->first << " : " << it->second << std::endl;

    std::cout << std::endl;

    numeros.erase("uno");

    std::cout << it->first << " : " << it->second << std::endl;

    std::cout << std::endl;

    auto it_2 = numeros.find("uno");
    std::cout << it_2->first << " : " << it_2->second << std::endl;

    std::cout << std::endl;

    for (auto i=numeros.begin(); i!=numeros.end(); ++i)
        std::cout << i->first << " : " << i->second << std::endl;

    return 0;
}

Output

uno : 1

uno : 1

uno : 1

dos : 2
tres : 3

Thank you!

Norv
  • 13
  • 1
  • 4
  • 2
    `erase` invalidates all current map iterators, if you dereference one after that happens then undefined behaviour is invoked. Also `it_2` will be an end iterator, again dereferncing it will invoke ub but you can test it to see if it's `numeros.end()` before dereferencing. – George Feb 02 '20 at 12:09
  • In my compiler `it_2` doesn't print `uno : 1`, it crashes. You should check it before use it. – masoud Feb 02 '20 at 12:11
  • Getting the correct result from dereferencing `it` after `erase`ing the element it points to is no guarantee that you are observing defined behavior. Indeed you are observing undefined behavior as @George pointed out. – Enlico Feb 02 '20 at 12:13
  • @masoud I use clang++ Apple clang version 11.0.0 It prints this output, but as walnut said, my program has undefined behaviour, under other compilers it can do anything. – Norv Feb 03 '20 at 18:21

1 Answers1

2

numeros.erase("uno"); invalidates the iterator it as per your quote. This means that you are not allowed to dereference the iterator anymore. Doing so anyway has undefined behavior.

Therefore your program has undefined behavior because you dereference the iterator in the next line

std::cout << it->first << " : " << it->second << std::endl;

Undefined behavior means your program could do anything. There are no guarantees that anything specific will happen anymore. There are no guarantees that you will get any error or warning either.


(Assuming you corrected the undefined behavior above:)

The second find in

auto it_2 = numeros.find("uno");

does not find the erased element. If .find does not find any element it returns the past-the-end iterator numeros.end(), which is what is happening here. Dereferencing the past-the-end iterator also has undefined behavior. So the following line

std::cout << it_2->first << " : " << it_2->second << std::endl;

which dereferences the past-the-end iterator also causes undefined behavior and your program to have no behavior guarantees.

You need to always check the result of find against end to verify that it found an element:

if(it_2 != numeros.end()) {
    std::cout << it_2->first << " : " << it_2->second << std::endl;
} else {
    std::cout << "uno not found!" << std::endl;
}
walnut
  • 21,629
  • 4
  • 23
  • 59
  • Yes that's it! I've check it with `.end()` => `if(it_2 == numeros.end()) { std::cout << "erased" << std::endl; }` it prints 'erased'. Then as you said both cases have undefined behaviour. My compiler printed the output I showed before, but in other circumstances or under other compilers it could do anything. (I use clang++ Apple clang version 11.0.0) – Norv Feb 03 '20 at 18:19