Mam kod, który wygląda następująco:
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);
Chciałbym usunąć nieaktywne elementy natychmiast po ich aktualizacji, aby uniknąć ponownego przeglądania listy. Ale jeśli dodam skomentowane wiersze, pojawia się błąd, gdy dochodzę do i++
: „Nie można zwiększać iteratora listy”. Wypróbowałem kilka alternatyw, które nie zwiększały się w wyciągu for, ale nie mogłem nic zrobić.
Jaki jest najlepszy sposób na usunięcie przedmiotów, gdy idziesz na std :: list?
Odpowiedzi:
Musisz najpierw zwiększyć iterator (z i ++), a następnie usunąć poprzedni element (np. Używając zwróconej wartości z i ++). Możesz zmienić kod na pętlę while w następujący sposób:
źródło
i = items.erase(i)
jest bezpieczniejsze, ponieważ jest równoważne z listą, ale nadal będzie działać, jeśli ktoś zmieni kontener na wektor. W przypadku wektora funkcja erase () przesuwa wszystko w lewo, aby wypełnić dziurę. Jeśli spróbujesz usunąć ostatni element z kodem, który przyrosty iterator po skasowaniu przemieszcza koniec do lewej, a porusza iteracyjnej do prawy-- minione końca. A potem upaść.Chcesz robić:
To poprawnie zaktualizuje iterator, aby wskazywał lokalizację po usuniętym iteratorze.
źródło
i==items.begin()
?i= items.erase(i);
. Jest to forma kanoniczna i już dba o wszystkie te szczegóły.Musisz wykonać kombinację odpowiedzi Kristo i MSN:
Oczywiście najbardziej wydajną i savy SuperCool® STL jest coś takiego:
źródło
Użyj algorytmu std :: remove_if.
Edycja: Praca ze zbiorami powinna wyglądać tak: 1. przygotować kolekcję. 2. zbieranie procesów.
Życie będzie łatwiejsze, jeśli nie pomieszacie tych kroków.
źródło
Oto przykład wykorzystujący
for
pętlę, która iteruje listę i zwiększa lub ponownie waliduje iterator w przypadku usunięcia elementu podczas przechodzenia przez listę.źródło
Alternatywa dla wersji pętli do odpowiedzi Kristo.
Tracisz trochę wydajności, cofasz się, a potem ponownie do przodu podczas usuwania, ale w zamian za dodatkowy przyrost iteratora możesz zadeklarować iterator w zakresie pętli, a kod będzie wyglądał na nieco czystszy. To, co wybrać, zależy od priorytetów chwili.
Odpowiedź była całkowicie spóźniona, wiem ...
źródło
iterator cannot be decremented
erase
random access iterator
forward only iterator
Mam podsumowanie, oto trzy metody z przykładem:
1. za pomocą
while
pętli2. przy użyciu
remove_if
funkcji członka na liście:3. użycie
std::remove_if
funkcji funtion w połączeniu zerase
funkcją członka:4. używając
for
pętli, należy pamiętać o aktualizacji iteratora:źródło
Usunięcie unieważnia tylko iteratory wskazujące na usunięte elementy.
Tak więc w tym przypadku po usunięciu * i, i jest unieważnione i nie można go zwiększać.
Co możesz zrobić, to najpierw zapisać iterator elementu, który ma zostać usunięty, następnie zwiększyć iterator, a następnie usunąć zapisany.
źródło
Jeśli myślisz o
std::list
podobnej kolejce, możesz usunąć kolejkę z kolejki i umieścić w kolejce wszystkie elementy, które chcesz zachować, ale tylko kolejkę (i nie kolejkę) z pozycji, którą chcesz usunąć. Oto przykład, w którym chcę usunąć 5 z listy zawierającej liczby 1-10 ...myList
będzie teraz mieć tylko numery 1-4 i 6-10.źródło
Iteracja do tyłu pozwala uniknąć efektu wymazania elementu na pozostałych elementach do przejścia:
PS: zobaczyć to , na przykład, w odniesieniu do tyłu iteracji.
PS2: Nie przetestowałem dokładnie, czy dobrze radzi sobie z usuwaniem elementów na końcach.
źródło
avoids the effect of erasing an element on the remaining elements
dla listy, prawdopodobnie tak. Dla wektora może nie. Nie jest to gwarantowane w przypadku dowolnych kolekcji. Na przykład mapa może podjąć decyzję o ponownym zrównoważeniu.Możesz pisać
Możesz napisać równoważny kod
std::list::remove_if
, który jest mniej szczegółowy i bardziej wyraźnystd::vector::erase
std::remove_if
Idiom powinny być stosowane, gdy przedmioty jest wektorem zamiast listy zachować compexity w O (n) - lub w przypadku pisania kodu rodzajowe i pozycji może być pojemnik bez skutecznego sposobu kasowania pojedynczych elementów (jak wektor)źródło
Myślę, że masz tam błąd, koduję w ten sposób:
źródło