2013-07-05 13 views
5

Sto iterando attraverso un QLinkedList utilizzando un ciclo foreach, ma ho bisogno di eliminare elementi se corrispondono a una determinata condizione. Qual è il modo corretto per farlo senza rovinare il ciclo?Modo corretto per modificare le strutture di dati Qt utilizzando il ciclo foreach

foreach(Object obj, myLinkedList) 
{ 
    if(obj.val == BAD_VAL) 
     // remove the item from myLinkedList 
} 

ho trovato other questions questo tipo di indirizzo di questo, ma non per il caso generale, come la lista collegata.

Vorrei sapere anche su altre strutture dati (come QSet, QHash, ecc.) Se possibile. Grazie

+0

@hyde Ho collegato a quella stessa domanda nella mia domanda, affermando che non ha affrontato la totalità di ciò che stavo chiedendo. C'è una differenza tra 'QList' e' QLinkedList'. Sono simili, ma * non * identici. –

+0

Bene, risponde alla domanda, per quanto posso vedere. Qt prende una copia superficiale del contenitore quando si usa il suo 'foreach'. Se si modifica la struttura dei contenitori originale, Qt deve creare una nuova copia profonda (copia sulla semantica di scrittura) del contenitore completo. In breve, non usare 'foreach' per questo. E la semantica è la stessa per ogni contenitore Qt. – hyde

risposta

14

Per il caso specifico:

Apparentemente foreach loop non devono essere utilizzati per modificare l'elenco a tutti, perché il ciclo foreach sta attualmente lavorando su una copia della lista originale. Se lo modifichi, non solo subisci una penalità a causa della condivisione implicita e modifica-on-write, ma le tue modifiche vengono scartate anche una volta che esci dal ciclo.

Il modo corretto per eseguire ciò è utilizzare un iteratore. Preferisco gli iteratori in stile Java. Noterai che esistono classi di iteratore per ogni tipo di elenco che forniscono iteratori semplici. Per l'esempio QLinkedList, esiste una classe QMutableLinkedListIterator. Può essere utilizzato come segue:

Dal Qt documentation con i miei commenti aggiunti:

QMutableLinkedListIterator<int> i(list); // pass list as argument 
while (i.hasNext()) { 
    int val = i.next();     // retrieve value of current item 
    if (val < 0) { 
     i.setValue(-val);    // change/set value of current item 
    } else if (val == 0) { 
     i.remove();      // delete current item 
    } 
} 


Per il caso generale:

Se si utilizza una struttura dati diversa da Qt QLinkedList, è probabile che esista una classe iteratore per te. Se si desidera modificare l'elenco, utilizzare la versione Mutevole. L'API è più o meno la stessa per ognuno di questi. Ecco le classi:

Structure | Immutable Case  | Mutable Case 
----------------------------------------------------- 
QList  | QListIterator  | QMutableListIterator 
QLinkedList | QLinkedListIterator | QMutableLinkedListIterator 
QHash  | QHashIterator  | QMutableHashIterator 
QMap   | QMapIterator   | QMutableMapIterator 
QSet   | QSetIterator   | QMutableSetIterator 
QStringList | QStringListIterator | QMutableStringListIterator 
QVector  | QVectorIterator  | QMutableVectorIterator 
0

Posso anche suggerire un modo costoso ma semplice per farlo. Crea un altro elenco e copia buoni oggetti. Quindi sostituire la vecchia lista con una nuova.

QLinkedList<Object> new_list; 
foreach(Object obj, myLinkedList) { 
    if(obj.val != BAD_VAL) { 
    new_list << obj; 
    } 
} 
list = new_list; 

Non farlo se il contenuto della lista è grande.