Bir kümeden geçmem ve önceden tanımlanmış bir kriteri karşılayan öğeleri kaldırmam gerekiyor.
Bu yazdığım test kodu:
#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;
}
İlk başta, kümeden bir öğeyi yineleyerek silmenin yineleyiciyi geçersiz kılacağını ve for döngüsündeki artışın tanımsız davranışa sahip olacağını düşündüm. Yine de bu test kodunu çalıştırdım ve her şey yolunda gitti ve nedenini açıklayamıyorum.
Sorum: Bu, standart kümeler için tanımlanmış davranış mı yoksa bu uygulamaya özel mi? Bu arada ubuntu 10.04'te (32 bit sürüm) gcc 4.3.3 kullanıyorum.
Teşekkürler!
Önerilen çözüm:
Bu, kümedeki öğeleri yinelemenin ve silmenin doğru bir yolu mu?
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;
}
}
Düzenleme: TERCİH EDİLEN ÇÖZÜM
Tam olarak aynı şeyi yapsa da, bana daha zarif görünen bir çözüm buldum.
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);
}
}
Süre içinde birkaç test koşulu varsa, her birinin yineleyiciyi artırması gerekir. Bu kodu daha çok seviyorum çünkü yineleyici yalnızca tek bir yerde artırılarak kodu daha az hataya açık ve daha okunaklı hale getiriyor.