Kluczowe wartości elementów w a std::setsą constnie bez powodu. Modyfikowanie ich może zniszczyć porządek, który jest niezbędny dla std::set.
Dlatego rozwiązaniem jest usunięcie iteratora i wstawienie nowego z kluczem *it - sub. Pamiętaj, że std::set::erase()zwraca nowy iterator, który musi być użyty w twoim przypadku, aby pętla while działała poprawnie.
#include<iostream>
#include<set>
template <typename T>
std::ostream& operator<<(std::ostream &out, const std::set<T> &values)
{
const char *sep = "{ ";
for (const T &value : values) { out << sep << value; sep = ", "; }
return out << " }";
}
int main()
{
std::set<int> test{ 11, 12, 13, 14, 15 };
std::cout << "test: " << test << '\n';
const int sub = 10;
std::set<int>::iterator iter = test.begin();
while (iter != test.end()) {
const int value = *iter;
iter = test.erase(iter);
test.insert(value - sub);
}
std::cout << "test: " << test << '\n';
}
Wynik:
test: { 11, 12, 13, 14, 15 }
test: { 1, 2, 3, 4, 5 }
Demo na żywo na coliru
Zmiany w std::settrakcie iteracji nie są ogólnie problemem, ale mogą powodować subtelne problemy.
Najważniejsze jest to, że wszystkie używane iteratory muszą pozostać nienaruszone lub nie można ich już używać. (Dlatego właśnie bieżącemu iteratorowi elementu kasującego przypisuje się wartość zwracaną, std::set::erase()która jest albo nienaruszonym iteratorem, albo końcem zestawu).
Oczywiście elementy można wstawić również za bieżącym iteratorem. Chociaż nie stanowi to problemu std::set, może przerwać pętlę mojego powyższego przykładu.
Aby to zademonstrować, zmieniłem nieco powyższą próbkę. Pamiętaj, że dodałem dodatkowy licznik, aby umożliwić zakończenie pętli:
#include<iostream>
#include<set>
template <typename T>
std::ostream& operator<<(std::ostream &out, const std::set<T> &values)
{
const char *sep = "{ ";
for (const T &value : values) { out << sep << value; sep = ", "; }
return out << " }";
}
int main()
{
std::set<int> test{ 11, 12, 13, 14, 15 };
std::cout << "test: " << test << '\n';
const int add = 10;
std::set<int>::iterator iter = test.begin();
int n = 7;
while (iter != test.end()) {
if (n-- > 0) {
const int value = *iter;
iter = test.erase(iter);
test.insert(value + add);
} else ++iter;
}
std::cout << "test: " << test << '\n';
}
Wynik:
test: { 11, 12, 13, 14, 15 }
test: { 23, 24, 25, 31, 32 }
Demo na żywo na coliru