As @BenjaminLindley and @JMerdich pointed out, for the problem stated, a two-pass approach is probably simpler and more efficient.
In a realistic situation, it is possible that there is some expensive calculation that needs to be done either to determine if an element is invalid or to determine if an element is the one we are looking for:
In which case a two-pass approach becomes less desirable because it causes us to do this expensive calculation twice.
But it is possible to do a single-pass approach without calling std::vector::erase
multiple times within the loop. It is not too hard to write std::remove_if
yourself, then we can get it to do both checks at the same time. We still just call std::vector::erase
once at the end:
std::vector<T>::iterator
findAndRemoveInvalid(std::vector<T>& vec, U whatImLookingFor) {
// Find first invalid element - or element you are looking for
auto first = vec.begin();
for(;first != vec.end(); ++first) {
auto result = someExpensiveCalculation(*first);
if (result == whatImLookingFor)
return first;
if (isInvalid(result))
break;
}
if (first == vec.end())
return first;
// Find subsequent valid elements - or element you are looking for
auto it = first + 1;
for(;it != vec.end(); it++) {
auto result = someExpensiveCalculation(*it);
if (result == whatImLookingFor)
break;
if (!isInvalid(result)) {
*first++ = std::move(*it); // shift valid elements to the start
continue;
}
}
// erase defunct elements and return iterator to the element
// you are looking for, or vec.end() if not found.
return vec.erase(first, it);
}
Live demo.
It is clearly more complicated though, so measure performance first.