Редактировать: Извините, оригинальная версия была неправильной. Исправлено.
Вот что происходит. Ваш ввод для remove_if
:
1 2 3 4 5 6
^ ^
begin end
А алгоритм remove_if
просматривает все числа от begin
до end
(включая begin
, но исключая end
) и удаляет все элементы между ними, которые соответствуют вашему предикату. Поэтому после запуска remove_if
ваш вектор выглядит следующим образом
1 2 3 ? 5 6
^ ^
begin new_end
Где ?
- это значение, которое я не считаю детерминированным, хотя, если оно гарантированно будет чем-либо, оно будет 4
. И new_end
, который указывает на новый конец введенной вами последовательности ввода , с соответствующими элементами теперь удаленными, это то, что возвращается std::remove_if
. Обратите внимание, что std::remove_if
не затрагивает ничего, кроме той последовательности, которую вы ему дали. Это может иметь больше смысла с более расширенным примером.
Скажите, что это ваш ввод:
1 2 3 4 5 6 7 8 9 10
^ ^
begin end
После std::remove_if
вы получите:
1 2 3 5 7 ? ? 8 9 10
^ ^
begin new_end
Подумайте об этом на мгновение. Что он сделал, так это удалил 4 и 6 из подпоследовательности, а затем сдвинул все в подпоследовательности вниз, чтобы заполнить удаленные элементы, а затем переместил итератор end
на новый конец та же подпоследовательность. Цель состоит в том, чтобы удовлетворить требование, чтобы полученная последовательность (begin
, new_end
] совпадала с подпоследовательностью (begin
, end
], которую вы передали, но с некоторыми удаленными элементами. или за end
, который вы прошли, осталось нетронутым.
От чего вы хотите избавиться, так это все, что находится между конечным итератором, который был возвращен, и исходным конечным итератором, который вы ему дали . Это ?
«мусорные» значения. Таким образом, ваш вызов удаления должен быть:
ints.erase(it, ints.begin()+4);
Призыв к erase
, который у вас есть, просто стирает все, что находится за концом подпоследовательности, для которой вы выполняли удаление, а это не то, что вам нужно.
Что усложняет это, так это то, что алгоритм remove_if
на самом деле не вызывает erase()
для вектора и не изменяет размер вектора в любой точке. Он просто перемещает элементы и оставляет некоторые «мусорные» элементы после окончания подпоследовательности, которую вы попросили обработать. Это кажется глупым, но единственная причина, по которой STL делает это таким образом, состоит в том, чтобы избежать проблемы с недействительными итераторами, которые были дважды вызваны (и иметь возможность работать с вещами, которые не являются контейнерами STL, например, с массивами). *