Hier ist mein Code:
while (it!=s.end()) //here 's' is a set of stl and 'it' is iterator of set
{
*it=*it-sub; //'sub' is an int value
it++;
}
Ich kann den Wert von set by iterator nicht aktualisieren. Ich möchte einen ganzzahligen Wert 'sub' von allen Elementen der Menge subtrahieren.
Kann mir jemand helfen, wo das eigentliche Problem liegt und was die eigentliche Lösung wäre?
Hier ist die Fehlermeldung:
error: assignment of read-only location ‘it.std::_Rb_tree_const_iterator<int>::operator*()’
28 | *it=*it-sub;
| ~~~^~~~~~~~
*it - sub
. Bitte beachten Sie, dassstd::set::erase()
ein neuer Iterator zurückgegeben wird, der in Ihrem Fall verwendet werden muss, damit diewhile
Schleife ordnungsgemäß funktioniert.Antworten:
Schlüsselwerte von Elementen in a
std::set
habenconst
einen guten Grund. Wenn Sie sie ändern, kann dies die Reihenfolge zerstören, die für astd::set
.Daher besteht die Lösung darin, den Iterator zu löschen und einen neuen mit Schlüssel einzufügen
*it - sub
. Bitte beachten Sie, dassstd::set::erase()
ein neuer Iterator zurückgegeben wird, der in Ihrem Fall verwendet werden muss, damit die while-Schleife ordnungsgemäß funktioniert.Ausgabe:
Live-Demo auf coliru
Änderungen
std::set
während der Iteration sind im Allgemeinen kein Problem, können jedoch subtile Probleme verursachen.Die wichtigste Tatsache ist, dass alle verwendeten Iteratoren intakt bleiben müssen oder nicht mehr verwendet werden dürfen. (Aus diesem Grund wird dem aktuellen Iterator des Löschelements der Rückgabewert zugewiesen, dessen Rückgabewert
std::set::erase()
entweder ein intakter Iterator oder das Ende der Menge ist.)Natürlich können auch Elemente hinter dem aktuellen Iterator eingefügt werden. Dies ist zwar kein Problem,
std::set
kann aber die Schleife meines obigen Beispiels durchbrechen.Um dies zu demonstrieren, habe ich das obige Beispiel ein wenig geändert. Bitte beachten Sie, dass ich einen zusätzlichen Zähler hinzugefügt habe, um die Beendigung der Schleife zu gewähren:
Ausgabe:
Live-Demo auf coliru
quelle
std::set
. Es kann erforderlich sein, den Grenzfall zu berücksichtigen, in dem der neue Iterator direkt hinter dem gelöschten eingefügt wird. - Es wird nach dem Einfügen in die Schleife übersprungen.extract
Knoten erstellen, ihre Schlüssel ändern und sie wieder in set zurücksetzen. Dies wäre effizienter, da unnötige Zuweisungen vermieden werden.std::set
. Da Sie nicht zweimal dasselbe Element haben können, bleibt beim Einfügenstd::set
das Element unverändert, und Sie verlieren das Element später. Betrachten Sie zum Beispiel den Eingabesatz:{10, 20, 30}
mitadd = 10
.Einfach durch ein anderes Set zu ersetzen
quelle
Sie können Elemente
std::set
von Design nicht mutieren . Sehenhttps://en.cppreference.com/w/cpp/container/set/begin
Das liegt daran, dass set sortiert ist . Wenn Sie ein Element in einer sortierten Sammlung mutieren, muss die Sammlung erneut sortiert werden, was natürlich möglich ist, aber nicht auf C ++ - Weise.
Ihre Optionen sind:
std::set
, ändern Sie es und fügen Sie es erneut ein. (Es ist keine gute Idee, wenn Sie jedes Element ändern möchten.)quelle
A
std::set
wird normalerweise als selbstausgleichender Binärbaum in STL implementiert.*it
ist der Wert des Elements, mit dem der Baum geordnet wird. Wenn es möglich wäre, es zu ändern, würde die Bestellung ungültig werden, daher ist dies nicht möglich.Wenn Sie ein Element aktualisieren möchten, müssen Sie dieses Element in der Menge finden, es entfernen und den aktualisierten Wert des Elements einfügen. Da Sie jedoch die Werte aller Elemente aktualisieren müssen, müssen Sie alle Elemente einzeln löschen und einfügen.
Es ist möglich, dies in einer bereitgestellten for-Schleife zu tun
sub > 0
.S.erase(pos)
Entfernt den Iterator an der Positionpos
und gibt die folgende Position zurück. Wennsub > 0
, wird der aktualisierte Wert, den Sie einfügen, vor dem Wert am neuen Iterator im Baum stehen, aber wennsub <= 0
, dann wird der aktualisierte Wert nach dem Wert am neuen Iterator im Baum stehen und Sie werden daher in einem Endlosschleife.quelle
Der Fehler erklärt das Problem ziemlich genau
Mitglieder des
std::set
Containers sindconst
. Wenn Sie sie ändern, wird ihre jeweilige Bestellung ungültig.Zum Ändern von Elementen in
std::set
, müssen Sie das Element löschen und nach dem erneut einfügen.Alternativ können Sie
std::map
dieses Szenario verwenden , um es zu überwinden.quelle