2011-06-21 16 views
15

Obecnie mają następujący pętli:iterator drugiego do ostatniego elementu w postaci listy

for(list<string>::iterator jt=it->begin(); jt!=it->end()-1; jt++) 

mam listę łańcuchów, które znajduje się w większej listy (list<list<string> >). Chcę przejrzeć zawartość listy wewnętrznej, aż dojdę do elementu od drugiego do ostatniego. Jest tak, ponieważ przetworzyłem już zawartość końcowego elementu i nie mam powodu, aby przetwarzać je ponownie.

Jednak użycie it->end()-1 jest nieprawidłowe - nie mogę tutaj użyć operatora . Chociaż mógłbym użyć operatora --, to zmniejszyłoby to końcowy iterator w każdym cyklu.

Uważam, że lista STL jest podwójnie połączoną listą, więc z mojej perspektywy powinno być możliwe zrobienie tego.

Porady? Z góry dziękuję

Odpowiedz

9

Requisite zalecenie do korzystania z biblioteki standardowej:

std::for_each(lst.begin(), --lst.end(), process); 

Jeśli nie chcesz kłopotów z tworzeniem funktor [I prawie nigdy nie] i nie można użyć odwrotnego iteratory, podnosić kontrolę końcową z pętli:

for(iterator i = lst.begin(), j = --lst.end(); i != j; ++i) { 
    // do 
    // stuff 
} 

Albo można po prostu zaufać optymalizator do uznania, że ​​nie trzeba trzymać odtwarzając stan końcowy, a nie sam podnosić. To, jak wiarygodne jest to działanie, zależy od implementacji list, tego, jak skomplikowany jest twój kod pętli i jak dobry jest twój optymalizator.

W każdym razie rób to, co najłatwiejsze do zrozumienia, i martw się wydajnością po zakończeniu.

+0

Doceniam prostotę tego rozwiązania. Tak, inne rozwiązania z odwrotnym iteratorem były miłe - ale twoje rozwiązanie nauczyło mnie metody bez użycia specjalnego iteratora. – BSchlinker

+0

"Jeśli nie chcesz kłopotów z tworzeniem funktora" - dziś polecam po prostu włożyć tam lambdę – Paladin

6

Iterator listy nie jest losowym iteratorem. należy wykonać następujące czynności:

if (! it->empty()) 
{ 
    list<string>::iterator test = it->end(); 
    --test; 
    for(list<string>::iterator jt = it->begin(); jt != test; ++jt) 
    { 
    ... 
    } 
} 

Jeszcze jedno: użyj ++jt przeciwko jt++. jt++ kod źródłowy zwykle wygląda mniej więcej tak:

iterator operator++ (int i) 
{ 
    iterator temp = (*this); 
    ++(*this); 
    return temp; 
}; 
4

Chociaż mogę używać - operatora, byłoby to zmniejszamy tę ostateczną iterator w każdym cyklu.

Nie, nie będzie. Otrzyma on kopię końcowego iteratora i zmniejszy go. To wszystko. Nie zmieniłoby to końcowego iteratora zapisanego na liście.

Twoim głównym problemem powinno być sprawdzenie, czy lista jest pusta , zapewniając, że istnieje --it-> koniec().

4

co z odwrotnym iteratorem?

for(list<string>::reverse_iterator jt=++(it->rbegin()); jt!=it->rend(); jt++) 
+0

To rzeczywiście skutkuje błędem ze względu na użycie „!” operator w komunikacie "jt! = it-> rend();" – BSchlinker

+0

Typ powinien być 'list :: reverse_iterator' zamiast tylko' list :: iterator'. –

+0

Nie byłeś świadomy odwrotnych iteratorów - dzięki! – BSchlinker

1

w C++ 11 i później, najlepszą odpowiedzią wydaje się być użycie std::prev

for(iterator i = lst.begin(); i != std::prev(lst.end()); ++i) { 
    // do 
    // stuff 
} 

Dokumentacja dla std :: poprz na http://en.cppreference.com/w/cpp/iterator/prev mówi

Chociaż wyrażenie - c.end() często kompiluje, nie jest to gwarantowane: c.end() jest wyrażeniem rvalue i nie ma wymogu iteratora, który określa, że ​​zmniejszenie wartości rwartu jest gwarantowane. W szczególności, gdy iteratory są implementowane jako wskaźniki, metoda -c.end() nie kompiluje się, podczas gdy std :: prev (c.end()) działa.

wierzę std :: prev() na pustej liście jest niezdefiniowane, więc może trzeba owinąć to w stanie !i.empty()

Powiązane problemy