Próbuję zrobić coś takiego:
for ( std::list< Cursor::Enum >::reverse_iterator i = m_CursorStack.rbegin(); i != m_CursorStack.rend(); ++i )
{
if ( *i == pCursor )
{
m_CursorStack.erase( i );
break;
}
}
Jednak usuwanie wymaga iteratora, a nie odwrotnego iteratora. czy istnieje sposób przekonwertowania odwrotnego iteratora na zwykły iterator lub inny sposób usunięcia tego elementu z listy?
i != m_CursorStack.rend()
. Zamiast tego piszi = m_CursorStack.rbegin(), end = m_CursorStack.rend(); i != end;
. Innymi słowy, zainicjuj iterator, który możesz przechowywać w celu powtórzenia porównania - zakładając, że pozycja końcowa nie zmieni się jako efekt uboczny twojego ciała pętli.std::remove
?Odpowiedzi:
Po kilku dalszych badaniach i testach znalazłem rozwiązanie. Najwyraźniej zgodnie ze standardem [24.4.1 / 1] związek między i.base () i i wynosi:
(z artykułu dr Dobbs ):
Musisz więc zastosować przesunięcie przy pobieraniu base (). Dlatego rozwiązaniem jest:
EDYTOWAĆ
Aktualizacja do C ++ 11.
reverse_iterator
i
pozostaje niezmieniony:reverse_iterator
i
jest zaawansowany:Uważam to za znacznie jaśniejsze niż moje poprzednie rozwiązanie. Użyj tego, czego potrzebujesz.
źródło
m_CursorStack.erase( (++i).base())
(człowiek, robienie tego z odwrotnymi iteratorami powoduje ból głowy ...). Należy również zauważyć, że artykuł DDJ znajduje się w książce Meyera „Effective STL”.*
je mieli, ale mówimy o tym, na który element wskazywałbyś, gdybyśbase
je używał, czyli jeden element po prawej stronie. Nie jestem fanem rozwiązań--(i.base())
ani(++i).base()
rozwiązań, ponieważ mutują one iterator. Wolę też,(i+1).base()
która działa.Należy pamiętać, że
m_CursorStack.erase( (++i).base())
może być problem, jeśli zostanie użyty wfor
pętli (patrz oryginalne pytanie), ponieważ zmienia wartość i. Prawidłowe wyrażenie tom_CursorStack.erase((i+1).base())
źródło
iterator j = i ; ++j
, ponieważi+1
nie działa na iteratorze, ale to jest właściwy pomysłm_CursorStack.erase(boost::next(i).base())
z Boost. lub w C ++ 11m_CursorStack.erase(std::next(i).base())
Wymaga to
-std=c++11
flagi (dlaauto
):źródło
Zabawne, że na tej stronie nie ma jeszcze właściwego rozwiązania. Tak więc następujące jest poprawne:
W przypadku iteratora do przodu rozwiązanie jest proste:
W przypadku iteratora wstecznego musisz zrobić to samo:
Uwagi:
reverse_iterator
z iteratorastd::list::erase
źródło
Podczas korzystania z
reverse_iterator
„sbase()
metody i zmniejszanie wynikiem tu pracuje, to warto zauważyć, żereverse_iterator
S nie podano ten sam status jak zwykłeiterator
s. Zasadniczo powinieneś preferować zwykłeiterator
sreverse_iterator
( s)const_iterator
orazconst_reverse_iterator
s (s) z dokładnie takich powodów. Zobacz doktora Dobbsa, aby uzyskać szczegółowe omówienie przyczyny.źródło
źródło
A oto fragment kodu, który przekształca wynik wymazywania z powrotem w odwrotny iterator w celu wymazania elementu w kontenerze podczas iteracji w odwrotnej kolejności. Trochę dziwne, ale działa nawet po skasowaniu pierwszego lub ostatniego elementu:
źródło
Jeśli nie musisz wymazywać wszystkiego w trakcie, a następnie rozwiązać problem, możesz użyć idiomu usuwania-usuwania:
std::remove
zamienia wszystkie elementy w kontenerze, które pasująpCursor
do końca, i zwraca iterator do pierwszego pasującego elementu. A późniejerase
użycie zakresu usunie się z pierwszego dopasowania i przejdzie do końca. Kolejność niepasujących elementów zostaje zachowana.Może to działać szybciej, jeśli używasz
std::vector
, gdzie wymazywanie w środku zawartości może wymagać dużo kopiowania lub przenoszenia.Lub oczywiście, powyższe odpowiedzi wyjaśniające użycie
reverse_iterator::base()
są interesujące i warte poznania, aby rozwiązać dokładnie określony problem, uważam, żestd::remove
lepiej pasuje.źródło
Chciałem tylko coś wyjaśnić: w niektórych z powyższych komentarzy i odpowiedzi przenośna wersja do wymazywania jest wymieniona jako (++ i) .base (). Jednak chyba, że coś mi brakuje, poprawną instrukcją jest (++ ri) .base (), co oznacza, że „zwiększasz” reverse_iterator (nie iterator).
Wczoraj wpadłem na potrzebę zrobienia czegoś podobnego i ten post był pomocny. Dziękuję wszystkim.
źródło
Aby uzupełnić odpowiedzi innych i ponieważ natknąłem się na to pytanie, szukając std :: string bez większego powodzenia, oto odpowiedź z użyciem std :: string, std :: string :: erase i std :: reverse_iterator
Mój problem polegał na usunięciu nazwy pliku obrazu z pełnego ciągu nazwy pliku. Pierwotnie został rozwiązany za pomocą std :: string :: find_last_of, ale badam alternatywny sposób z std :: reverse_iterator.
Używa algorytmu, iteratora i nagłówków ciągów.
źródło
iterator do tyłu jest dość trudny w użyciu. Właśnie użyłem ogólnego iteratora. „r” Zaczyna się od ostatniego elementu. Gdy znajdziesz coś do usunięcia. usuń go i zwróć następny iterator. np. po usunięciu trzeciego elementu wskaże bieżący czwarty element. i nowy trzeci. Dlatego należy zmniejszyć 1, aby przejść w lewo
źródło