Для того, что бы удалить эелемент из контейнера типа vector, string, list или deque мы пользуемся методом erase, которому параметром передаём итератор на ненужный элемент.
В какое то время, происходит оптимизация кода или же изначально закладывается возможность поиска ненужного элемента с помощью алгоритма STL remove_if.
Далее код обрастает использованием boost::bind для удобства и прочими артефактами.
И тут в какой то момент становится нужно удалять не один элемент, а несколько. Неважно, в новом коде, или же расширяя возможности старого. И здесь многие новички в C++ делают ошибку, не зная и не посмотрев в документацию метода erase. Они копируют по примеру код, написанный ранее и переделывают условие поиска элементов для remove_if. Но они забывают, что если методу erase передаётся один аргумент, то этот метод удаляет именно тот элемент, итератор на который был передан аргументом.
Для удаления нескольких элементов существует перегруженный метод erase, который принимает два аргумента — на начало и конец итеративной последовательности, подлежащей удалению. В большинстве случаев, когда используется алгоритм remove_if, он реорганизует последовательность так, что все элементы не подлежащие удалению переставляются в начало контейнера. Например, у нас есть vector
1 2 3 1 2 3 1 2 3
Если вызвать
bool IsTwo (int i) { return (i == 2); }
tstart = remove_if(v.begin(), v.end(), isTwo)
//удалить элемент со значением 2 из контейнера v
получится
1 3 1 3 1 3 ? ? ?
где ? — некий мусор. Итератор tstart, который возвратит remove_if, будет указывать на первый мусорный элемент, в этом случае на третий с конца. Мусорные элементы могут иметь те же значения, что и до вызова remove_if, то есть 1 2 3, а могут иметь и любые другие, на это полагаться не стоит. Размер контейнера остается неизменным.
Таким образом, если мы запишем полный кусок кода, с которым работает новичок, то получится следующее:
v.erase(remove_if(v.begin(), v.end(), isTwo));
Соответственно erase удаляет первый мусорный элемент и изменяет размер контейнера на единицу. В результате содержимое контейнера начинает выглядеть так:
1 3 1 3 1 3 ? ?
что является неправильным и соответственно приводит к непредсказуемым последствиям при дальнейшей работе с этим контейнером.
Как же не допускать такого? Когда, разработчик не уверен в своих знаниях, то хорошим тоном будет проверить их по документации и узнать, что если вызвать erase таким образом:
v.erase(remove_if(v.begin(), v.end(), isTwo), v.end());
то все мусорные элементы будут удалены.
Если же разработчик уверен (иногда случается ложная уверенность, это нормально), то тестирование всё равно никогда не бывает лишним. Причём не ленимся, и пишем пограничные варианты тестов в том числе. В нашем случае, мы должны проверить на вскидку не только правильность удаления одного элемента, но также нескольких, и ни одного, и конечно же случай, когда контейнер вообще пуст.