Edit: Sorry, the original version was incorrect. Fixed.
This is what happens. Your entry in remove_if :
1 2 3 4 5 6 ^ ^ begin end
And the remove_if algorithm remove_if through all the numbers between begin and end (including begin , but excluding end ), and removes all the elements between them that match your predicate. So after remove_if is executed, your vector is as follows
1 2 3 ? 5 6 ^ ^ begin new_end
Where ? is a value that I do not consider deterministic, although if it is guaranteed, it will be 4 . And new_end , which points to the new end of the input sequence you gave it, with matching elements removed, is what std::remove_if . Note that std::remove_if doesn't touch anything beyond the subsequence you gave it. This may be of greater importance in a more extended example.
Say this is your input:
1 2 3 4 5 6 7 8 9 10 ^ ^ begin end
After std::remove_if you will get:
1 2 3 5 7 ? ? 8 9 10 ^ ^ begin new_end
Think about it for a moment. What he did is remove 4 and 6 from the subsequence, and then slide everything inside the subsequence down to fill in the deleted elements, and then move the end iterator to the new end of the same subsequence. The goal is to satisfy the requirement that the sequence ( begin , new_end ] that it produces matches the subsequence ( begin , end ] that you passed, but with some deleted elements. Or outside the end that you passed, remains untouched.
What you want to get rid of this is all between the returned final iterator and the original final iterator that you gave it. ? these values ? "trash". So your removal request should be:
ints.erase(it, ints.begin()+4);
The erase call that you just deleted because of the end of the subsequence that you performed the removal that you do not want here.
What complicates this is that the remove_if algorithm does not actually call erase() on the vector or does not change the size of the vector at any point. It simply moves the elements around and leaves some garbage items after the end of the subsequence that you asked to process. This seems silly, but the whole reason STL does it this way is to avoid the problem with invalid iterators that grew doublep (and be able to run on things that are not STL containers, such as raw arrays).