Vor einiger Zeit hatte ich eine Diskussion mit einem Kollegen darüber, wie Werte in STL- Maps eingefügt werden . Ich habe es vorgezogen,
map[key] = value;
weil es sich natürlich anfühlt und klar zu lesen ist, während er es vorgezogen hat
map.insert(std::make_pair(key, value))
Ich habe ihn nur gefragt und keiner von uns kann sich an den Grund erinnern, warum Insert besser ist, aber ich bin sicher, dass es nicht nur eine Stilvorliebe war, sondern dass es einen technischen Grund wie Effizienz gab. In der SGI STL-Referenz heißt es einfach: "Genau genommen ist diese Mitgliedsfunktion nicht erforderlich: Sie existiert nur zur Vereinfachung."
Kann mir jemand diesen Grund nennen oder träume ich nur davon, dass es einen gibt?
Antworten:
Wenn du schreibst
Es gibt keine Möglichkeit zu sagen, ob Sie ersetzt die
value
fürkey
, oder wenn Sie erstellt eine neuekey
mitvalue
.map::insert()
wird nur erstellen:Bei den meisten meiner Apps ist es mir normalerweise egal, ob ich sie erstelle oder ersetze, daher verwende ich die leichter lesbaren
map[key] = value
.quelle
(res.first)->second
alsvalue
auch im zweiten Fall zu verwenden.else
weil ich denke, dass die Verwendungvalue
klarer ist als der Iterator. Nur wenn der Typ des Werts einen ungewöhnlichen Kopierer oder op == hätte, wäre dies anders, und dieser Typ würde andere Probleme bei der Verwendung von STL-Containern wie map verursachen.map.insert(std::make_pair(key,value))
sollte seinmap.insert(MyMap::value_type(key,value))
. Der Typ, der von zurückgegeben wird,make_pair
stimmt nicht mit dem Typ überein, der von genommen wird,insert
und die aktuelle Lösung erfordert eine Konvertierungoperator[]
haben. Vergleichen Sie einfach die Größe vorher und nachher. Esmap::operator[]
ist viel wichtiger, nur konstruierbare Standardtypen aufrufen zu können .Die beiden haben unterschiedliche Semantiken, wenn es um den Schlüssel geht, der bereits in der Karte vorhanden ist. Sie sind also nicht direkt vergleichbar.
Für die Version operator [] muss der Wert jedoch standardmäßig erstellt und anschließend zugewiesen werden. Wenn dies also teurer ist als die Kopierkonstruktion, ist dies teurer. Manchmal macht die Standardkonstruktion keinen Sinn, und dann ist es unmöglich, die operator [] -Version zu verwenden.
quelle
Eine andere Sache zu beachten
std::map
:myMap[nonExistingKey];
erstellt einen neuen Eintrag in der Karte, der mit verschlüsselt istnonExistingKey
auf einen Standardwert initialisiert ist.Das erschreckte mich zum Teufel, als ich es das erste Mal sah (während ich meinen Kopf gegen einen bösen alten Käfer schlug). Hätte es nicht erwartet. Für mich sieht das nach einer Get-Operation aus, und ich habe den "Nebeneffekt" nicht erwartet. Bevorzugen Sie,
map.find()
wenn Sie von Ihrer Karte kommen.quelle
Wenn der Leistungstreffer des Standardkonstruktors kein Problem darstellt, wählen Sie aus Liebe zu Gott die besser lesbare Version.
:) :)
quelle
insert
ist aus Sicht der Ausnahmesicherheit besser.Der Ausdruck
map[key] = value
besteht eigentlich aus zwei Operationen:map[key]
- Erstellen eines Kartenelements mit Standardwert.= value
- Kopieren des Wertes in dieses Element.Im zweiten Schritt kann eine Ausnahme auftreten. Infolgedessen wird die Operation nur teilweise ausgeführt (ein neues Element wurde zur Karte hinzugefügt, aber dieses Element wurde nicht mit initialisiert
value
). Die Situation, in der eine Operation nicht abgeschlossen ist, der Systemstatus jedoch geändert wird, wird als Operation mit "Nebenwirkung" bezeichnet.insert
Betrieb gibt eine starke Garantie, bedeutet, dass es keine Nebenwirkungen hat ( https://en.wikipedia.org/wiki/Exception_safety ).insert
ist entweder vollständig erledigt oder die Karte bleibt unverändert.http://www.cplusplus.com/reference/map/map/insert/ :
quelle
Wenn Ihre Anwendung geschwindigkeitskritisch ist, empfehle ich die Verwendung des Operators [], da insgesamt 3 Kopien des Originalobjekts erstellt werden, von denen 2 temporäre Objekte sind und früher oder später als zerstört wurden.
In insert () werden jedoch 4 Kopien des Originalobjekts erstellt, von denen 3 temporäre Objekte (nicht unbedingt "temporäre") sind und zerstört werden.
Dies bedeutet zusätzliche Zeit für: 1. Zuweisung eines Objektspeichers 2. Ein zusätzlicher Konstruktoraufruf 3. Ein zusätzlicher Destruktoraufruf 4. Eine Freigabe des Objektspeichers
Wenn Ihre Objekte groß sind, Konstruktoren typisch sind, Destruktoren viel Ressourcen freisetzen, zählen die obigen Punkte noch mehr. In Bezug auf die Lesbarkeit denke ich, dass beide fair genug sind.
Die gleiche Frage kam mir in den Sinn, aber nicht über die Lesbarkeit, sondern über die Geschwindigkeit. Hier ist ein Beispielcode, durch den ich den Punkt kennengelernt habe, den ich erwähnt habe.
quelle
insert
muss die gleiche Suche durchführen, also kein Unterschied zu[]
(weil Kartenschlüssel eindeutig sind).In C ++ 11 denke ich, dass der beste Weg, ein Paar in eine STL-Map einzufügen, ist:
Das Ergebnis ist ein Paar mit:
Das erste Element (result.first) zeigt auf das eingefügte Paar oder auf das Paar mit diesem Schlüssel, wenn der Schlüssel bereits vorhanden ist.
Zweites Element (result.second), true, wenn die Einfügung korrekt oder falsch war, ist ein Fehler aufgetreten.
PS: Wenn Sie sich nicht für die Bestellung interessieren, können Sie std :: unordered_map verwenden;)
Vielen Dank!
quelle
Ein Problem mit map :: insert () ist, dass es keinen Wert ersetzt, wenn der Schlüssel bereits in der Map vorhanden ist. Ich habe C ++ - Code gesehen, der von Java-Programmierern geschrieben wurde, bei denen erwartet wurde, dass sich insert () genauso verhält wie Map.put () in Java, wo Werte ersetzt werden.
quelle
Ein Hinweis ist, dass Sie auch Boost.Assign verwenden können :
quelle
Hier ist ein weiteres Beispiel zeigt , dass
operator[]
überschreibt den Wert für den Schlüssel , wenn es vorhanden ist , aber.insert
nicht überschreiben Sie den Wert , wenn es vorhanden ist .quelle
Dies ist ein eher eingeschränkter Fall, aber nach den Kommentaren, die ich erhalten habe, halte ich es für erwähnenswert.
Ich habe in der Vergangenheit gesehen, dass Leute Karten in Form von verwenden
Um Fällen von versehentlichem Überschreiben von Werten auszuweichen, schreiben Sie dann einige andere Code-Teile ein:
Ihr Grund dafür war, wie ich mich erinnere, dass sie sicher waren, dass sie in diesen bestimmten Codebits keine Kartenwerte überschreiben würden; Fahren Sie daher mit der besser lesbaren Methode fort
[]
.Ich hatte noch nie direkte Probleme mit dem Code, der von diesen Leuten geschrieben wurde, aber ich bin bis heute der festen Überzeugung, dass Risiken - so gering sie auch sein mögen - nicht eingegangen werden sollten, wenn sie leicht vermieden werden können.
Verwenden Sie in Fällen, in denen es sich um Kartenwerte handelt, die unbedingt nicht überschrieben werden dürfen
insert
. Machen Sie keine Ausnahmen nur zur besseren Lesbarkeit.quelle
insert
(nichtinput
), da dieconst_cast
alle vorherigen Wert verursacht überschrieben werden, was sehr nicht-const. Oder markieren Sie den Werttyp nicht alsconst
. (So etwas ist normalerweise das ultimative Ergebnis vonconst_cast
, daher ist es fast immer eine rote Fahne, die auf einen Fehler an einer anderen Stelle hinweist.)insert
in Fällen empfehlen, in denen Sie verhindern möchten, dass Werte überschrieben werden. (Gerade geändert,input
uminsert
- danke)const_cast<T>(map[key])
1. [] ist besser lesbar, 2. sie vertrauen auf bestimmte Codebits, sie überschreiben keine Werte und 3. sie tun es nicht Ich möchte, dass andere Teile unwissenden Codes ihre Werte überschreiben - daher dieconst value
.const_cast
scheint die zusätzliche "Lesbarkeit" von mehr als zu negieren[]
, und diese Art von Vertrauen ist fast Grund genug, einen Entwickler zu entlassen. Schwierige Laufzeitbedingungen werden durch kugelsichere Designs gelöst, nicht durch Bauchgefühle.Die Tatsache, dass die
insert()
Funktion std :: map den mit dem Schlüssel verknüpften Wert nicht überschreibt, ermöglicht es uns, Objektaufzählungscode wie folgt zu schreiben:Es ist ein ziemlich häufiges Problem, wenn wir einige nicht eindeutige Objekte einigen IDs im Bereich 0..N zuordnen müssen. Diese IDs können später beispielsweise in Diagrammalgorithmen verwendet werden. Alternative mit
operator[]
würde meiner Meinung nach weniger lesbar aussehen:quelle