Назад к вопросамЧто не так с этим циклом, который удаляет нули из
JuniorДебаггингОчень часто
Что не так с этим циклом, который удаляет нули из v?
#include <vector>
void drop_zeros(std::vector<int>& v) {
for (auto it = v.begin(); it != v.end(); ++it) {
if (*it == 0) {
v.erase(it);
}
}
}erase делает it недействительным, и ++it — неопределённое поведение
- Ждать только пропуска элемента: после
v.erase(it)итераторitнедействителен, и даже++itдля него — неопределённое поведение. - Ждать, что
v.end()вычисляется один раз: условие вызывает его на каждой итерации, так что ошибка — в недействительномit, а не в устаревшем конце.
- Почему удаление из середины
std::vectorдороже, чем удаление последнего элемента? - Как функция
std::erase_ifиз C++20 заменяет этот цикл?
Исправление
erase возвращает итератор на элемент, который шёл за удалённым. Присвойте его it, а ++it выполняйте, только если элемент не удалили:
#include <vector>
void drop_zeros(std::vector<int>& v) {
for (auto it = v.begin(); it != v.end();) {
if (*it == 0) {
it = v.erase(it);
} else {
++it;
}
}
}