through - parse a map c++




Come posso eliminare elementi di una std:: map con un iteratore? (2)

Se hai un compilatore compatibile con C ++ 11, ecco un modo semplice per farlo:

std::map<K, V>::iterator itr = myMap.begin();
while (itr != myMap.end()) {
    if (ShouldDelete(*itr)) {
       itr = myMap.erase(itr);
    } else {
       ++itr;
    }
}

L'idea è quella di far avanzare l'iteratore dall'inizio del contenitore fino alla fine, controllando ad ogni passaggio se la coppia chiave / valore attuale debba essere cancellata. In tal caso, rimuoveremo l'elemento iterato utilizzando la funzione membro di erase , che restituisce un iteratore all'elemento successivo nella mappa. Altrimenti, avanza normalmente l'iteratore.

Se non hai un compilatore compatibile con C ++ 11, o stai lavorando con una base di codice più vecchia, le cose sono un po 'più complicate. Prima del C ++ 11, la funzione membro di erase non restituiva un iteratore all'elemento successivo nella mappa. Ciò significava che per rimuovere un elemento durante l'iterazione, era necessario utilizzare un ballo in tre parti:

  1. Copia l'iteratore corrente.
  2. Avanza l'iteratore corrente sull'elemento successivo.
  3. Chiamare erase sulla copia del vecchio iteratore.

Questo è mostrato qui:

std::map<K, V>::iterator itr = myMap.begin();
while (itr != myMap.end()) {
    if (ShouldDelete(*itr)) {
       std::map<K, V>::iterator toErase = itr;
       ++itr;
       myMap.erase(toErase);
    } else {
       ++itr;
    }
}

Questo processo era necessario perché se hai appena chiamato erase sull'iteratore, lo invaliderei , il che significa che operazioni come l'incremento e il decremento porterebbero a un comportamento indefinito. Il codice precedente aggira questo problema impostando una copia dell'iteratore, facendo avanzare itr modo che si trovi all'elemento successivo, quindi cancellando la copia temporanea dell'iteratore.

Usando una Clever Trickiness, è possibile ridurre questo codice a scapito della leggibilità. Il seguente schema è comune nel vecchio codice C ++, ma non è necessario in C ++ 11:

std::map<K, V>::iterator itr = myMap.begin();
while (itr != myMap.end()) {
    if (ShouldDelete(*itr)) {
       myMap.erase(itr++);  // <--- Note the post-increment!
    } else {
       ++itr;
    }
}

L'uso dell'operatore post-incremento qui è un modo intelligente di fare una copia del vecchio iteratore (ricorda che un operatore postfix ++ restituisce una copia del valore iteratore originale) mentre avanza anche il precedente iteratore.

Vorrei scorrere un programma std::map ed eliminare elementi in base al loro contenuto. Quanto sarebbe meglio questo?



Questo è un modo semplice:

    int value_to_delete( 2 );
    for( std::map<int, int>::iterator i = mm.begin(); i != mm.end(); ) {
        if( i->second != value_to_delete ) {
            mm.erase( i++ ); // advance before iterator become invalid
        }
        else {
            ++i;
        }
    }




stdmap