Ich habe einen (C ++ 14) Code, der so aussieht:
map<int, set<string>> junk;
for (int id : GenerateIds()) {
try {
set<string> stuff = GetStuff();
junk[id] = stuff;
} catch (const StuffException& e) {
...
}
}
Das funktioniert. Löst manchmal GetStuff()
eine Ausnahme aus, die gut funktioniert, da ich dann keinen Wert in der Junk-Map haben möchte.
Aber zuerst hatte ich das in die Schleife geschrieben, was nicht funktioniert:
junk[id] = GetStuff();
Genauer gesagt, selbst wenn GetStuff()
eine Ausnahme ausgelöst wird, junk[id]
wird sie erstellt (und eine leere Menge zugewiesen).
Das würde ich nicht erwarten: Ich würde erwarten, dass sie genauso funktionieren.
Gibt es ein Prinzip von C ++, das ich hier missverstanden habe?
junk[id]
erstellt ein neuesset
, ja, aber das verwendet den Standardkonstruktor. Deshalb ist das Set leer. Diese leere Menge wäre als Objekt zum Zuweisen verwendet worden, wennGetStuff()
dies erfolgreich gewesen wäre. Die Ausnahme ist jedoch genau, warum keine Zuordnung erfolgt. Das Set bleibt im Standardzustand. Es ist ein richtiges C ++ - Objekt, und Sie können seine Mitglieder normal aufrufen. Dhjunk[id].size()
wird danach 0 sein.junk[id] = std::move(stuff);
.Antworten:
Vor C ++ 17 gab es keine Sequenzierung zwischen der linken und rechten Seite der Zuweisungsoperatoren.
In C ++ 17 wurde erstmals eine explizite Sequenzierung eingeführt (die rechte Seite wird zuerst ausgewertet).
Dies bedeutet, dass die Bewertungsreihenfolge nicht angegeben ist. Dies bedeutet, dass die Implementierung die Bewertung in der gewünschten Reihenfolge durchführen muss. In diesem Fall wird zuerst die linke Seite bewertet.
Weitere Einzelheiten finden Sie in dieser Referenz zur Bewertungsreihenfolge (insbesondere unter Punkt 20).
quelle
junk[id]
bewirkt das oben erwähnte Einfügen und danach sind schonGetStuff()
Würfe passiert . Beachten Sie, dass in C ++ 14 die Reihenfolge, in der diese Dinge geschehen, durch die Implementierung definiert ist. Mit einem anderen Compilerjunk[id] = GetStuff();
können Sie das Einfügen möglicherweise nicht durchführen, wennGetStuff()
Würfe ausgeführt werden.quelle
Sie verstehen falsch, wie es
operator[]
funktioniertstd::map
.Es gibt einen Verweis auf das zugeordnete Element zurück. Daher fügt Ihr Code zuerst ein Standardelement an dieser Position ein und ruft dann auf
operator=
, um einen neuen Wert festzulegen.Damit dies wie erwartet funktioniert, müssen Sie
std::map::insert
(*) verwenden:junk.insert(std::make_pair(id, GetStuff()));
Vorsichtsmaßnahme :
insert
Fügt den Wert nur hinzu, wenn erid
noch nicht zugeordnet ist.quelle
operator[]
funktioniert. Auch aus Ihrer Antwort ist nicht klar, warumoperator=
die linke Seite bewertet, auch wenn die rechte Seite eine Ausnahmeoperator[]
selbst ein leerer Satz erstellt werden würdejunk[id]
.