Выбор ответа Middle Контейнеры STL изнутри спрашивают часто обновлено

Удаление в цикле по итератору

Вопрос

Как правильно удалить из std::vector<int> v все чётные элементы в цикле по итераторам?

Попробуйте сами

Выберите вариант, и откроется разбор.

Показать ответ и разбор

Коротко

Правильный ответ: for (auto it = v.begin(); it != v.end();) { if (it % 2 == 0) it = v.erase(it); else ++it; }. erase инвалидирует итератор на удалённый элемент и все после него, но возвращает итератор на следующий элемент.

Варианты ответа

  1. for (auto it = v.begin(); it != v.end(); ++it) if (*it % 2 == 0) v.erase(it);
  2. for (int x : v) if (x % 2 == 0) v.erase(std::find(v.begin(), v.end(), x));
  3. for (auto it = v.begin(); it != v.end();) { if (*it % 2 == 0) it = v.erase(it); else ++it; }правильный ответ
  4. Удалять в цикле нельзя ни в каком виде: только скопировать нечётные в новый вектор и обменять их

Разбор

erase инвалидирует итератор на удалённый элемент и все после него, но возвращает итератор на следующий элемент. Его и надо использовать. Ещё лучше одной строкой: std::erase_if(v, [](int x) { return x % 2 == 0; }); (C++20), это O(n) вместо O(n²).

  • Во втором варианте после erase выполняется ++it по недействительному итератору: UB.
  • В третьем range-for держит итераторы, которые инвалидирует erase: UB.
  • Удалять можно, нужно правильно обновлять итератор.

Ответьте сами, а не прочитайте

В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.