Frage zur Exceptionsicherheit bei std::map
-
Ich für meinen Teil würde aller Wahrscheinlichkeit
std::map<int, std::string> mymap; mymap[123];
schreiben und auf die pointer verzichten. Die auto_ptr-Konstruktion ist jedenfalls recht sinnlos, dan kannste auch gleich
std::string *p = new std::string; try { mymap[123] = p; } catch(...) { delete p; }
schreiben.
-
Wenn die Basisgarantie ausreicht, einfach einen Sequence Point einfügen:
string*& ref = mymap[123]; ref = new string;
-
Kann denn der op[] überhaupt ne Exception werfen?
-
Ja, er muss ja neue Knoten allozieren -> bad_alloc möglich.
-
Bashar schrieb:
Wenn die Basisgarantie ausreicht, einfach einen Sequence Point einfügen:
string*& ref = mymap[123]; ref = new string;
Das habe ich ja noch nie gesehen... Was heißt "die Basisgarantie ausreicht"?
Aber wenn dieser operator eine exception wirft, ist doch eh alles zu spät.
-
GotW #59 schrieb:
1. Basic Guarantee: If an exception is thrown, no resources are leaked, and objects remain in a destructible and usable -- but not necessarily predictable -- state. This is the weakest usable level of exception safety, and is appropriate where client code can cope with failed operations that have already made changes to objects' state.
-
Das gilt allerdings nur für das Objekt, dass die Exception geschmissen hat.
-
0xdeadbeef schrieb:
Das gilt allerdings nur für das Objekt, dass die Exception geschmissen hat.
Basisgarantie heißt: auch im Exception-Fall gehen keine Ressourcen verloren und die Anwendung landet in einem konsistenten Zustand. Damit bezieht sich die Garantie auf alle Objekte.
-
0xdeadbeef schrieb:
Das gilt allerdings nur für das Objekt, dass die Exception geschmissen hat.
Objekte werfen keine Exceptions, Funktionen tun das.
-
@Bashar: das hatte ich mir verkniffen.
-
Dann halt das Objekt, dessen Methode die Exception geschmissen hat, ansonsten gilt die Basisagrantie für diesen Fall nicht mehr so ohne weiteres. Stell dir folgenden Code vor:
struct A { A() { throw 1; } }; struct B { }; void do_something(A &a, B *b) { ... } do_something(A(), new B());
An das eben erstelle B-Objekt kommst du nicht mehr dran, also wirst du es auch nicht wieder los.
Wenn die Basisgarantie meinte, dass das B-Objekt noch irgendwo im Speicher liegt - ok, das ist richtig. Aber dann ist sie für diese Fragestellung völlig unerheblich.
-
Dein Code erfüllt die Basisgarantie nicht.
Nochmal langsam zum mitschreiben: Basisgarantie bedeutet: keine Resource-Leaks + konsister Zustand auch im Fall von Exceptions.Für alle Objekte. Gilt es nicht für alle Objekte, so ist die Basisgarantie auch nicht gegeben.
-
0xdeadbeef schrieb:
Dann halt das Objekt, dessen Methode die Exception geschmissen hat
So pedantisch wollte ich gar nicht sein. Alle Objekte, die in einer Funktion bearbeitet werden, müssen in einem konsistenten Zustand verbleiben, damit diese Funktion die Basisgarantie erfüllt. Zusätzlich darf es nicht zu Leaks kommen.
-
Also habe ich mich nicht geirrt, es ist tatsächlich nicht exception-sicher.
volkard schrieb:
oder nach was hübschem, nämlicher ner map, die nicht die strings besitzt.
Wer besitzt die strings(*) denn dann?
Wenn man ein Objekt nicht auf dem Stack unterbringen kann, wird's wohl in irgendeinem Container landen; aber das angesprochene Problem hat man ja auch z. B. bei myVector.push_back(new Object);(*) auch stellvertretend für Fälle, in denen man nur Zeiger auf die (Basis-)Klasse hat