Я столкнулся с проблемой, когда мне нужно удалить последние элементы вектора, пока не будет выполнено определенное условие (для примера, пусть это будет элемент, не равный нулю)
Я написал этот код, он делает свое дело —
Но я бы предпочел найти алгоритм STL, который я могу использовать (я могу использовать find_if и затем стереть, но я бы хотел цикл один раз через элементы, которые я удаляю …)
Кроме того, я боюсь, что я могу вызвать здесь какой-то UB, должен ли я волноваться?
Решение
Ваш код может быть проще:
С помощью std::remove или же std::remove_if удалит все элементы на основе критериев, поэтому вы должны использовать std::find_if как Влад дал в своем ответе.
Другие решения
Вот пример. Он использует общую идиому для стирания векторов
У меня есть std::vector , и я хочу удалить n-й элемент. Как это сделать?
Чтобы удалить один элемент, вы можете сделать:
Или, чтобы удалить сразу несколько элементов:
Метод стирания на std::vector перегружен, поэтому, возможно, более ясный вызов
когда вы хотите удалить только один элемент.
Метод erase будет использоваться двумя способами:
Стирание одного элемента:
Стирание диапазона элементов:
На самом деле функция erase работает для двух профилей:
Удаление одного элемента
Удаление диапазона элементов
Так как std:: vec.begin() отмечает начало контейнера, и если мы хотим удалить i-й элемент в нашем векторе, мы можем использовать:
Если вы посмотрите внимательно, vec.begin() — это просто указатель на начальную позицию нашего вектора и добавление значения я к нему увеличивает указатель на позицию i, поэтому вместо этого мы можем получить доступ к указателю на i-й элемент по:
Итак, мы можем написать:
Если у вас есть неупорядоченный вектор, вы можете воспользоваться тем, что он неупорядочен и использует то, что я видел у Дэна Хиггинса в CPPCON
Поскольку порядок списка не имеет значения, просто возьмите последний элемент в списке и скопируйте его поверх элемента, который хотите удалить, затем нажмите и удалите последний элемент.
Если вы работаете с большими векторами (размером > 100 000) и хотите удалить множество элементов, я бы рекомендовал сделать что-то вроде этого:
Код принимает каждое число в vec, которое не может быть разделено на 3 и копирует его в vec2. Затем он копирует vec2 в vec. Это довольно быстро. Для обработки 20 000 000 элементов этот алгоритм занимает всего 0,8 с!
Я сделал то же самое с методом erase, и это занимает много и много времени:
Чтобы удалить элемент, используйте следующий способ:
Для более широкого обзора вы можете посетить: http://www.cplusplus.com/reference/vector/vector/erase/
Предыдущие ответы предполагают, что у вас всегда есть подписанный индекс. К сожалению, std::vector использует size_type для индексирования и difference_type для арифметики итератора, поэтому они не работают вместе, если вы включили "-Wconversion" и друзей. Это еще один способ ответить на вопрос, имея возможность обрабатывать как подписанные, так и unsigned:
Вот еще один способ сделать это, если вы хотите удалить элемент, найдя его с его значением в векторе, вам просто нужно сделать это на векторе.
это удалит ваше значение отсюда. Спасибо
Как насчет этого?
Я предлагаю прочитать это, так как я считаю, что это то, что вы ищете. https://en.wikipedia.org/wiki/Erase%E2%80%93remove_idiom
Если вы используете, например,
Вы удалите n -th элемент вектора, но при удалении второго элемента все остальные элементы вектора будут смещены, а размер вектора будет равен -1. Это может быть проблемой, если вы перебираете вектор, поскольку vector size() уменьшается. Если у вас есть проблема, подобная этой, предложенная ссылка предложила использовать существующий алгоритм в стандартной библиотеке C++. и "удалить" или "удалить_if".
Подскажите, как корректно пройтись по вектору и удалить некоторые его элементы.
Т.е., корректно ли выполнять такие действия?
Или возникнут проблемы с итератором после удаления первого элемента?
Прочитал комментарии, всем спасибо за помощь
Пересмотрел код и понял, что не совсем полно поставил задачу:
Если воспользоваться советом @Harry, то тогда код можно же преобразовать к такому:
4 ответа 4
? Как по мне — понятнее и никаких проблем с итераторами. Вероятно, еще и быстрее, чем убирать по одному элементу.
Если перепишете check так, чтоб работал наоборот — то и лямбда-выражение (или bind ) не потребуется.
Если уж позарез нужен цикл — то воспользуйтесь тем, что erase возвращает итератор на элемент, следующий за удаленным:
Но учтите, что тут сложность — квадратичная, в отличие от remove_if (спасибо @pavel).