Gotchas:
When removing elements from containers, be careful not to saw off the branch on which you are sitting.
There is a big danger that you will remove an element to which your iterator is referring.
For example:
std::map<std::string,float> coll;
...
for (auto pos = coll.begin(); pos != coll.end(); ++pos) {
if (pos->second == value) {
coll.erase(pos); // RUNTIME ERROR !!!
}
}
Calling erase() for the element to which you are referring with pos invalidates pos as an iterator
of coll. Thus, if you use pos after removing its element without any reinitialization, all bets are off.
In fact, calling ++pos results in undefined behavior.
Solution:
(1) Since C++11, erase() always returns the value of the following element.
for (auto pos = coll.begin(); pos != coll.end(); ) {
if (pos->second == value) {
pos = coll.erase(pos); // possible only since C++11
}
else {
++pos;
}
}
(2) Before C++11, it was a design decision not to return the following position, because if not needed, it costs unnecessary time.
// remove all elements having a certain value
for (pos = coll.begin(); pos != coll.end(); ) {
if (pos->second == value) {
coll.erase(pos++);
}
else {
++pos;
}
}