Рассмотрим этот вектор:
|0|1|2|3|4|5|6|7|8|9|
Мы используем remove_if
, чтобы удалить все элементы, кратные 4:
std::remove_if(v.begin(), v.end(), [](auto i){ return i != 0 && !(i%4); });
Это начинается итерации через вектор с помощью итератора X до тех пор, пока он не найдет элемент, где предикат возвращает true:
|0|1|2|3|4|5|6|7|8|9|
X
Это первый элемент, который мы хотим удалить.
Далее он создает еще один итератор, указывающий на следующий элемент, Y = X + 1, и проверяет предикат для * Y:
|0|1|2|3|4|5|6|7|8|9|
X Y
предикат является ложным, поэтому мы хотим, чтобы этот элемент, так он назначает следующий элемент к элементу, который мы хотим удалить, выполнив *X = std::move(*Y)
:
|0|1|2|3|5|5|6|7|8|9|
X Y *X = std::move(*Y)
Таким образом, мы имеем два итератора, X и Y, где X указывает на следующий элемент в «выход» (т.е. элементы мы не удаляем), а Y - следующий элемент для удаления.
Двигаемся как итераторы на следующую позицию, проверить предикат для Y (который является ложным снова), и сделать другое назначение:
|0|1|2|3|5|6|6|7|8|9|
X Y *X = std::move(*Y)
Затем он делает то же самое снова на следующей позиции:
|0|1|2|3|5|6|7|7|8|9|
X Y *X = std::move(*Y)
а потом она движется, но считает, что предикат истинен для Y
|0|1|2|3|5|6|7|7|8|9|
X Y
S о это только увеличивает Y, который пропускает этот элемент и поэтому не копирует его в положение «выход» на X:
|0|1|2|3|5|6|7|7|8|9|
X Y
предикат не относится к Y, поэтому он присваивает его X:
|0|1|2|3|5|6|7|9|8|9|
X Y *X = std::move(*Y)
Тогда приращение X и Y снова
|0|1|2|3|5|6|7|9|8|9|
X Y
Теперь Y является пришедшим к концу так мы возвращаемся X (что указует на пришедший к концу выходной последовательности, то есть элементы, которые мы хотим держать).
После remove_if
возвращает X мы называем v.erase(X, v.end())
, поэтому вектор вызывает деструкторы для каждого элемента из X до конца:
|0|1|2|3|5|6|7|9|~|~|
X end
А затем устанавливает размер поэтому вектор заканчивается на X:
|0|1|2|3|5|6|7|9|
end
После этого v.capacity() >= v.size()+2
, поскольку память, которая использовалась двумя конечными элементами, по-прежнему присутствует, но не используется.
Сложность 'std :: remove_if()' is * Exactly std :: distance (first, last) приложения предиката *, как описано [в документации] (http://en.cppreference.com/w/CPP/алгоритм/удалить). –
'vector :: erase' не вызывает перераспределения в этом случае. – PaulMcKenzie
* "Если стирание попытается удалить из X в myVector.end(), это будет O (n^2)" * .... Как именно? – Nawaz