
Figo
Ich finde den Update-Vorgang an std::set
mühsam, da es keine solche API gibt cpReferenz. Also, was ich derzeit mache, ist ungefähr so:
//find element in set by iterator
Element copy = *iterator;
... // update member value on copy, varies
Set.erase(iterator);
Set.insert(copy);
Grundsätzlich kehrt der Iterator vorbei zurück Set
ist ein const_iterator
und Sie können seinen Wert nicht direkt ändern.
Gibt es einen besseren Weg, dies zu tun? Oder vielleicht sollte ich überschreiben std::set
indem ich mein eigenes erstelle (von dem ich nicht genau weiß, wie es funktioniert..)

Terry Mahaffey
set
kehrt zurück const_iterators
(Die Norm sagt set<T>::iterator
ist const
und das set<T>::const_iterator
und set<T>::iterator
kann tatsächlich derselbe Typ sein – siehe 23.2.4/6 in n3000.pdf), da es sich um einen bestellten Container handelt. Wenn es regelmäßig zurückkehrte iterator
könnten Sie den Artikelwert unter dem Container ändern, wodurch möglicherweise die Reihenfolge geändert wird.
Ihre Lösung ist die idiomatische Art, Elemente in a zu ändern set
.

Matthias M.
C++17 eingeführt extract
siehe Barrys Antwort.
Wenn Sie mit einer älteren Version festsitzen, gibt es im einfachen Fall 2 Möglichkeiten, dies zu tun:
- Sie können verwenden
mutable
auf die Variable, die nicht Teil des Schlüssels sind
- Sie können Ihre Klasse in a aufteilen
Key
Value
Paar (und verwenden Sie a std::map
)
Nun stellt sich die Frage nach dem kniffligen Fall: Was passiert eigentlich, wenn das Update das ändert key
Teil des Objekts? Ihr Ansatz funktioniert, obwohl ich zugeben muss, dass es langweilig ist.

Barry
In C ++ 17 können Sie es besser machen mit extract()
Dank an P0083:
// remove element from the set, but without needing
// to copy it or deallocate it
auto node = Set.extract(iterator);
// make changes to the value in place
node.value() = 42;
// reinsert it into the set, but again without needing
// to copy or allocate
Set.insert(std::move(node));
Dies vermeidet eine zusätzliche Kopie Ihres Typs und eine zusätzliche Zuweisung/Aufhebung der Zuweisung und funktioniert auch mit Nur-Verschiebe-Typen.
Du kannst auch extract
per Schlüssel. Wenn der Schlüssel fehlt, wird ein leerer Knoten zurückgegeben:
auto node = Set.extract(key);
if (node) // alternatively, !node.empty()
{
node.value() = 42;
Set.insert(std::move(node));
}

Avakar
Aktualisieren: Obwohl das Folgende ab sofort zutrifft, wird das Verhalten als a Defekt und wird in der kommenden Version des Standards geändert. Wie sehr traurig.
Es gibt mehrere Punkte, die Ihre Frage ziemlich verwirrend machen.
- Funktionen können Werte zurückgeben, Klassen nicht.
std::set
ist eine Klasse und kann daher nichts zurückgeben.
- Wenn Sie anrufen können
s.erase(iter)
dann iter
ist kein const_iterator
. erase
erfordert einen nicht konstanten Iterator.
- Alle Mitgliedsfunktionen von
std::set
die einen Iterator zurückgeben, geben einen nicht konstanten Iterator zurück, solange die Menge ebenfalls nicht konstant ist.
Sie dürfen den Wert eines Elements einer Menge ändern, solange die Aktualisierung die Reihenfolge der Elemente nicht ändert. Der folgende Code wird kompiliert und funktioniert einwandfrei.
#include <set>
int main()
{
std::set<int> s;
s.insert(10);
s.insert(20);
std::set<int>::iterator iter = s.find(20);
// OK
*iter = 30;
// error, the following changes the order of elements
// *iter = 0;
}
Wenn Ihr Update die Reihenfolge der Elemente ändert, müssen Sie sie löschen und erneut einfügen.
Vielleicht möchten Sie eine verwenden std::map
stattdessen. Verwenden Sie den Teil von Element
das wirkt sich auf die Bestellung des Schlüssels aus und legt alle ab Element
als Wert. Es wird einige geringfügige Datenduplizierungen geben, aber Sie werden einfachere (und möglicherweise schnellere) Aktualisierungen haben.

Bitmaske
Ich bin in C ++ 11 auf dasselbe Problem gestoßen, wo in der Tat ::std::set<T>::iterator
ist konstant und erlaubt daher nicht, seinen Inhalt zu ändern, auch wenn wir wissen, dass die Transformation die nicht beeinflusst <
unveränderlich. Sie können dies umgehen, indem Sie wickeln ::std::set
in ein mutable_set
Geben oder schreiben Sie einen Wrapper für den Inhalt:
template <typename T>
struct MutableWrapper {
mutable T data;
MutableWrapper(T const& data) : data(data) {}
MutableWrapper(T&& data) : data(data) {}
MutableWrapper const& operator=(T const& data) { this->data = data; }
operator T&() const { return data; }
T* operator->() const { return &data; }
friend bool operator<(MutableWrapper const& a, MutableWrapper const& b) {
return a.data < b.data;
}
friend bool operator==(MutableWrapper const& a, MutableWrapper const& b) {
return a.data == b.data;
}
friend bool operator!=(MutableWrapper const& a, MutableWrapper const& b) {
return a.data != b.data;
}
};
Ich finde das viel einfacher und es funktioniert in 90% der Fälle, ohne dass der Benutzer überhaupt merkt, dass etwas zwischen dem Satz und dem tatsächlichen Typ liegt.

Entwickler Null
Das geht in manchen Fällen schneller:
std::pair<std::set<int>::iterator, bool> result = Set.insert(value);
if (!result.second) {
Set.erase(result.first);
Set.insert(value);
}
Steht der Wert meist nicht schon in der std::set
dann kann dies eine bessere Leistung haben.
9902500cookie-checkC++ std::set update ist mühsam: Ich kann ein Element nicht an Ort und Stelle ändernyes
Erstellen Sie eine Inline-Funktion, wenn Sie der Meinung sind, dass die Verwendung von 2 Anweisungen bereits mühsam ist.
– kennytm
7. Februar 2010 um 19:02 Uhr
KennyTM hat den Nagel auf den Kopf getroffen. Es gibt keine Nachteile in Bezug auf die Leistung, also mach es einfach schon! 😛
– j_random_hacker
7. Februar 2010 um 19:24 Uhr
Wenn Sie eine Update-Funktion schreiben, möchten Sie diese vielleicht genauso modellieren wie Boost.MultiIndex: boost.org/doc/libs/release/libs/multi_index/doc/tutorial/…
– Emil Cormier
7. Februar 2010 um 21:55 Uhr
cplusplus.com ist eine schreckliche Referenz. Aspekte der Sprache “langweilig” zu finden, weil es … seltsam erscheint.
– Leichtigkeitsrennen im Orbit
12. Juni 2011 um 22:24 Uhr
Ich denke, der Nachteil dieses Ansatzes besteht darin, dass bei gleichzeitiger Verarbeitung eine Lese-/Schreibsperre aktiviert wird.
– UchihaItachi-Inaktives-Konto
31. Mai 2018 um 8:59 Uhr