Ich muss einen Satz durchgehen und Elemente entfernen, die vordefinierte Kriterien erfüllen.
Dies ist der Testcode, den ich geschrieben habe:
#include <set>
#include <algorithm>
void printElement(int value) {
std::cout << value << " ";
}
int main() {
int initNum[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
std::set<int> numbers(initNum, initNum + 10);
// print '0 1 2 3 4 5 6 7 8 9'
std::for_each(numbers.begin(), numbers.end(), printElement);
std::set<int>::iterator it = numbers.begin();
// iterate through the set and erase all even numbers
for (; it != numbers.end(); ++it) {
int n = *it;
if (n % 2 == 0) {
// wouldn't invalidate the iterator?
numbers.erase(it);
}
}
// print '1 3 5 7 9'
std::for_each(numbers.begin(), numbers.end(), printElement);
return 0;
}
Zuerst dachte ich, dass das Löschen eines Elements aus der Menge während des Durchlaufens den Iterator ungültig machen würde und das Inkrement in der for-Schleife ein undefiniertes Verhalten hätte. Obwohl ich diesen Testcode ausgeführt habe und alles gut gelaufen ist, kann ich nicht erklären, warum.
Meine Frage: Ist dies das definierte Verhalten für Standardmengen oder ist diese Implementierung spezifisch? Ich benutze übrigens gcc 4.3.3 unter Ubuntu 10.04 (32-Bit-Version).
Vielen Dank!
Vorgeschlagene Lösung:
Ist dies eine korrekte Methode zum Iterieren und Löschen von Elementen aus der Menge?
while(it != numbers.end()) {
int n = *it;
if (n % 2 == 0) {
// post-increment operator returns a copy, then increment
numbers.erase(it++);
} else {
// pre-increment operator increments, then return
++it;
}
}
Bearbeiten: BEVORZUGTE LÖSUNG
Ich bin auf eine Lösung gekommen, die mir eleganter erscheint, obwohl sie genau das Gleiche tut.
while(it != numbers.end()) {
// copy the current iterator then increment it
std::set<int>::iterator current = it++;
int n = *current;
if (n % 2 == 0) {
// don't invalidate iterator it, because it is already
// pointing to the next element
numbers.erase(current);
}
}
Wenn innerhalb der Weile mehrere Testbedingungen vorliegen, muss jede den Iterator erhöhen. Ich mag diesen Code besser, weil der Iterator nur an einer Stelle inkrementiert wird , wodurch der Code weniger fehleranfällig und lesbarer wird.
++it
sollte etwas effizienter sein, als it++
weil keine unsichtbare temporäre Kopie des Iterators verwendet werden muss. Kornels Version sorgt zwar länger dafür, dass die nicht gefilterten Elemente am effizientesten durchlaufen werden.