2011-12-23 14 views
37

Jestem nowy w Qt i próbuję nauczyć się idiomów.Jak mogę usunąć elementy z QList podczas iteracji za pomocą foreach?

The foreach documentation mówi:

Qt automatycznie wykonuje kopię pojemnika, gdy wchodzi do pętli foreach. Jeśli zmodyfikujesz kontener w trakcie iteracji, nie wpłynie to na pętlę.

Ale to nie znaczy jak aby usunąć element podczas iteracji z foreach. Mój najlepszy przypuszczenie jest coś takiego:

int idx = 0; 
foreach (const Foo &foo, fooList) { 
    if (bad(foo)) { 
    fooList.removeAt(idx); 
    } 
    ++idx; 
} 

Wydaje brzydki musiał zakresu idx zewnątrz pętli (i musiał utrzymać oddzielny licznik pętli w ogóle).

Również wiem, że foreach sprawia kopię QList, który jest tani, ale to, co się dzieje, kiedy już usunąć element - jest to, że nadal tanie lub drogie jest tam kopia na modyfikowanie dzieje? Tak, deep copy happens.

EDIT: To też nie wydaje się idiomatyczne Qt.

for (int idx = 0; idx < fooList.size();) { 
    const Foo &foo = fooList[idx]; 
    if (bad(foo)) { 
    fooList.removeAt(idx); 
    } 
    else ++idx; 
} 
+1

Dlaczego chcesz użyć 'foreach 'do tego? – Mat

+0

@Mat, nie muszę używać 'foreach', to po prostu wydaje się być przyjemne w użyciu, a dokumenty wydawały się sugerować, że jest jakiś sposób, aby to zrobić. Wydaje mi się, że Qt jest tak dobrze przemyślany, że wydaje mi się oczywisty idiom dla tego, co próbuję zrobić. – Dan

+0

Co z pustym QMutableListIterator :: remove()? http://developer.qt.nokia.com/doc/qt-4.8/qmutablelistiterator.html#remove –

Odpowiedz

38

powinny lepiej use iterators na to:

// Remove all odd numbers from a QList<int> 
QMutableListIterator<int> i(list); 
while (i.hasNext()) { 
    if (i.next() % 2 != 0) 
     i.remove(); 
} 
+2

Dokumenty mówią "standard w aplikacjach Qt ... wygodniejszy niż STL ... nieco mniej wydajny". OK, 2 na 3 nie jest złe. Dziękuję Ci! – Dan

16

Jeśli nie chcesz kopię w ogóle używać iteratorów. Coś jak:

QList<yourtype>::iterator it = fooList.begin(); 
while (it != fooList.end()) { 
    if (bad(*it)) 
    it = fooList.erase(it); 
    else 
    ++it; 
} 

(I upewnij się, że naprawdę chcesz użyć QList zamiast QLinkedList.)

foreach jest naprawdę miłe, gdy chcesz przemierzać kolekcję dla kontroli, ale jak znalazłeś , trudno jest uzasadnić, kiedy chcesz zmienić strukturę podstawowej kolekcji (nie wartości przechowywane tam). Dlatego unikam go w tym przypadku, po prostu dlatego, że nie mogę się dowiedzieć, czy jest bezpieczny, ani ile ma to miejsce podczas kopiowania.

+0

W większości sytuacji nie należy obawiać się używania QList zamiast QLinkedList. QList faktycznie przechowuje wszystkie swoje elementy również jako wskaźniki. W związku z tym dołączanie, wstawianie lub usuwanie elementów nie jest tak kosztowne, jak w QVector. – UndeadKernel

8

Jeśli funkcja testu jest wklęsłego, można również użyć QtConcurrent usunąć „złego” elementy:

#include <QtCore/QtConcurrentFilter> 
... 
QtConcurrent::blockingFilter(fooList, bad); 

lub wariant STL:

#include <algorithm> 
... 
fooList.erase(std::remove_if(fooList.begin(), fooList.end(), bad), 
       fooList.end());