Back to questionsWhat is wrong with this loop that removes zeros from
JuniorDebuggingVery common
What is wrong with this loop that removes zeros from v?
#include <vector>
void drop_zeros(std::vector<int>& v) {
for (auto it = v.begin(); it != v.end(); ++it) {
if (*it == 0) {
v.erase(it);
}
}
}erase invalidates it, so the next ++it is undefined behavior
- Expecting only a skipped element: after
v.erase(it)the iteratoritis invalid, so even++iton it is undefined behavior. - Expecting
v.end()to be read once: the condition calls it on every iteration, so the bug is the invalidit, not a stale end.
- Why does erasing from the middle of a
std::vectorcost more than erasing its last element? - How does the C++20 function
std::erase_ifreplace this loop?
Fix
erase returns an iterator to the element that followed the erased one. Assign it to it, and run ++it only when no element was erased:
#include <vector>
void drop_zeros(std::vector<int>& v) {
for (auto it = v.begin(); it != v.end();) {
if (*it == 0) {
it = v.erase(it);
} else {
++it;
}
}
}