I recently came across a bit of code that was essentially a ‘find and erase’ process on a std::map that essentially boiled down to the following:
typedef std::map<int, int> MyMap;
MyMap my_map;
MyMap::iterator end = my_map.end();
for (MyMap::iterator i = my_map.begin(); i != end; ++i) {
// Search for some value within the loop.
if (i->second = 5){
i = my_map.erase(i);
}
}
On Visual Studio 2008 this will even compile. However, for those of you who may be moving code over to GCC you may find there’s an issue that results in errors similar to the following:
error: no match for 'operator=' in (...) // Followed by a lot of stl template errors.
The answer is simple: erase doesn’t return an iterator… it returns void! A simple adjustment to the algorithm and everything compiles nicely on all compilers:
typedef std::map<int, int> MyMap;
MyMap my_map;
MyMap::iterator end = my_map.end();
for (MyMap::iterator i = my_map.begin(); i != end; ++i) {
// Search for some value within the loop.
if (i->second = 5){
my_map.erase(i++); // Increment the iterator
}
}
Here a post increment is used (to avoid incrementing first and erasing the item after the desired one!) to ensure the loop continues on successfully.
UPDATE
Sometime after writing this I was working on testing code where a single element was being added to a standard container and then removed through a method similar to the above. Doing so generates an error like the ones below:
map iterator not incrementable
OR
list iterator not incrementor
The reason for the error is that calling erase(i++) on the last element in a container sets i to the end() value. When the next iteration of the for loop comes around the iterator attempts to move one past the end and that’s when the assertion is hit. This can be fixed by revising the above solution and moving the iterator incrementation from the for header to it’s body. With that change here is the final solution:
</div> <div id="_mcePaste" style="position: absolute; left: -10000px; top: 992px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;">typedef std::map<int, int> MyMap;</div> <div id="_mcePaste" style="position: absolute; left: -10000px; top: 992px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;">MyMap my_map;</div> <div id="_mcePaste" style="position: absolute; left: -10000px; top: 992px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;">MyMap::iterator end = my_map.end();</div> <div id="_mcePaste" style="position: absolute; left: -10000px; top: 992px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;">for (MyMap::iterator i = my_map.begin(); i != end;) {</div> <div id="_mcePaste" style="position: absolute; left: -10000px; top: 992px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;"><span style="white-space: pre;"> </span>// Search for some value within the loop.</div> <div id="_mcePaste" style="position: absolute; left: -10000px; top: 992px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;"><span style="white-space: pre;"> </span>if (i->second = 5){</div> <div id="_mcePaste" style="position: absolute; left: -10000px; top: 992px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;"><span style="white-space: pre;"> </span>my_map.erase(i++); // Increment the iterator</div> <div id="_mcePaste" style="position: absolute; left: -10000px; top: 992px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;"><span style="white-space: pre;"> </span>} else {</div> <div id="_mcePaste" style="position: absolute; left: -10000px; top: 992px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;"><span style="white-space: pre;"> </span>++i;</div> <div id="_mcePaste" style="position: absolute; left: -10000px; top: 992px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;"><span style="white-space: pre;"> </span>}</div> <div id="_mcePaste" style="position: absolute; left: -10000px; top: 992px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;">}</div> <div id="_mcePaste" style="position: absolute; left: -10000px; top: 992px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;">typedef std::map<int, int> MyMap; MyMap my_map; MyMap::iterator end = my_map.end(); for (MyMap::iterator i = my_map.begin(); i != end;) { // Search for some value within the loop. if (i->second = 5){ my_map.erase(i++); // Increment the iterator } else { ++i; } }