У меня есть код, который выглядит так:
for (std::list<item*>::iterator i=items.begin();i!=items.end();i++)
{
bool isActive = (*i)->update();
//if (!isActive)
// items.remove(*i);
//else
other_code_involving(*i);
}
items.remove_if(CheckItemNotActive);
Я хотел бы удалить неактивные элементы сразу после их обновления, чтобы избежать повторного просмотра списка. Но если я добавляю закомментированные строки, я получаю сообщение об ошибке i++
: «Итератор списка не может быть увеличен». Я пробовал несколько альтернатив, которые не увеличивались в выражении for, но я не мог заставить что-либо работать.
Какой лучший способ удалить элементы, когда вы ходите по стандартному списку?
Ответы:
Сначала нужно увеличить итератор (с помощью i ++), а затем удалить предыдущий элемент (например, используя возвращаемое значение из i ++). Вы можете изменить код на цикл while следующим образом:
источник
i = items.erase(i)
более безопасно, поскольку оно эквивалентно списку, но все равно будет работать, если кто-то изменит контейнер на вектор. С вектором erase () перемещает все влево, чтобы заполнить отверстие. Если вы попытаетесь удалить последний элемент с кодом, который увеличивает итератор после стирания, конец перемещается влево, а итератор перемещается вправо - после конца. И тогда ты терпишь крах.Вы хотите сделать:
Это правильно обновит итератор, чтобы он указывал на местоположение после итератора, который вы удалили.
источник
i==items.begin()
?i= items.erase(i);
. Это каноническая форма, которая уже заботится обо всех этих деталях.Вам нужно сделать комбинацию ответа Кристо и MSN:
Конечно, самая эффективная и полезная вещь SuperCool® STL будет выглядеть примерно так:
источник
Используйте алгоритм std :: remove_if.
Редактировать: Работа с коллекциями должна быть такой: 1. Подготовить коллекцию. 2. процесс сбора.
Жизнь будет проще, если вы не будете смешивать эти шаги.
источник
Вот пример использования
for
цикла, который выполняет итерацию списка и увеличивает или повторно проверяет итератор в случае удаления элемента во время обхода списка.источник
Альтернатива петлевой версии ответу Кристо.
Вы теряете некоторую эффективность, вы возвращаетесь назад и затем снова вперед при удалении, но в обмен на дополнительное приращение итератора вы можете объявить итератор в области видимости цикла, и код выглядит немного чище. Что выбрать, зависит от приоритетов на данный момент.
Ответ был совершенно не вовремя, я знаю ...
источник
iterator cannot be decremented
erase
random access iterator
forward only iterator
Я суммирую это, вот три метода с примером:
1. используя
while
цикл2. используя
remove_if
функцию участника в списке:3. используя функцию
std::remove_if
объединения вerase
функции-член:4. используя
for
цикл, обратите внимание на обновление итератора:источник
Удаление делает недействительными только итераторы, которые указывают на удаляемые элементы.
Таким образом, в этом случае после удаления * i, я становится недействительным, и вы не можете делать приращение на нем.
Что вы можете сделать, это сначала сохранить итератор элемента, который нужно удалить, затем увеличить итератор и затем удалить сохраненный.
источник
Если вы думаете о
std::list
подобной очереди, то вы можете удалить из очереди и поставить в очередь все элементы, которые вы хотите сохранить, но только удалить из очереди (а не поставить в очередь) элемент, который вы хотите удалить. Вот пример, где я хочу удалить 5 из списка, содержащего числа 1-10 ...myList
теперь будет иметь только номера 1-4 и 6-10.источник
Повторение в обратном направлении устраняет эффект стирания элемента на оставшихся элементах, которые необходимо пройти:
PS: смотрите это , например, относительно обратной итерации.
PS2: я не проверил тщательно, хорошо ли он стирает элементы на концах.
источник
avoids the effect of erasing an element on the remaining elements
для списка, вероятно, да. Для вектора, возможно, нет. Это не гарантировано для произвольных коллекций. Например, карта может решить перебалансировать себя.Ты можешь написать
Вы можете написать эквивалентный код с
std::list::remove_if
, который менее подробный и более явныйstd::vector::erase
std::remove_if
Идиомы следует использовать , когда элементы вектора вместо списка , чтобы сохранить в макеты O (N) - или в случае , если вы пишете общий код и элементы могут быть контейнером, без эффективного способа удаления отдельных элементов (как вектор)источник
Я думаю, что у вас есть ошибка, я кодирую таким образом:
источник