Status zurücksetzen bei Exceptions
-
Hi, wie löst man das folgende Problem idiomatisch?
void f(int& a) { a = 5; try { g(); // kann throwen } catch (...) { a = 7; throw; } a = 7; }Also ich hab' dann so verschiedene Funktionen, in denen ich gewisse Variablen zuerst auf einen bestimmten Wert bringe, dann eine Funktion aufrufe, die werfen kann, und am Schluss sollt' ich die Variablen wieder in einen anderen Zustand bringen, egal ob die Funktion warf oder nicht.
Normalerweise macht man sich da ja RAII zum Vorteil, aber in jeder Funktion eine lokale Klasse zu schreiben und in dieser Klasse Zeiger auf alle Elemente des Scopes zu speichern finde ich extremst hässlich.Also, wie löst man das am besten?
-
ich geh mal davon aus, das dein beispiel nicht genau das wiederspiegelt was du wirklich hast.
die funktion g in deinem beispiel bekommt nichts von a mit. weiters wirfst du die exception einfach weiter.
also gleich am anfang auf 7 setzen und die exception erst gar nicht fangen:void f(int& a) { a = 7; g(); }
-
Ich weiß nicht so genau, was Du meinst! Aber warum verschiebst Du nicht einfach das "throw"dahin wo Du es haben möchtest oder wirfst die Exception einfach nicht weiter.
zu spät!
-
Schau dir mal folgendes Video an. Ab 1h06m:
https://channel9.msdn.com/Shows/Going+Deep/C-and-Beyond-2012-Andrei-Alexandrescu-Systematic-Error-Handling-in-CKurz: nimm einen ScopeGuard, der a=7 setzt.
Oder: nimm SCOPE_EXIT wie ab 1:17 erklärt.Du findest eine mögliche Implementierung dazu in https://github.com/facebook/folly/blob/master/folly/ScopeGuard.h
-
@Meep Meep:
Ja, bisschen ein unglücklich geratenes Beispiel. Wenn's hingegen g(a) lautet statt g(), sollte die Problematik aber korrekt reflektiert werden vom Beispiel (nun davon ausgehend, dass g(5) nicht geht).@Helmut.Jakoby:
Ich muss die Exception natürlich weiterwerfen. Ich kann den Fehlerfall ja nicht einfach lebendig begraben...@wob:
Danke, genau sowas hab ich gesucht!
-
Ichweißdochauchnicht schrieb:
Also ich hab' dann so verschiedene Funktionen, in denen ich gewisse Variablen zuerst auf einen bestimmten Wert bringe, dann eine Funktion aufrufe, die werfen kann, und am Schluss sollt' ich die Variablen wieder in einen anderen Zustand bringen, egal ob die Funktion warf oder nicht.
Wieso muss das so sein?
-
wob schrieb:
Kurz: nimm einen ScopeGuard, der a=7 setzt.
Oder: nimm SCOPE_EXIT wie ab 1:17 erklärt.
Ich möchte bloss anmerken: ich würde
SCOPE_EXITnur eingeschränkt empfehlen. Es ist ein gutes Werkzeug, aber ich sehe es öfter mal "overused". Sobald man die selbe Funktionalität an 2-3 Stellen braucht, sollte man sie raustrennen. Je nachdem was es ist halt in Hilfsfunktionen, Hilfsklassen oder auch Hilfsmakros.Und im Falle von mehreren
SCOPE_EXITmit der selben Funktion gehört einfach eine passende, spezialisierteScopeGuardKlasse her. Alles andere ist mMn. eine üble DRY Verletzung.Ichweißdochauchnicht schrieb:
Normalerweise macht man sich da ja RAII zum Vorteil, aber in jeder Funktion eine lokale Klasse zu schreiben und in dieser Klasse Zeiger auf alle Elemente des Scopes zu speichern finde ich extremst hässlich.
Du brauchst bloss eine Klasse. Bzw. vermutlich ein Klassentemplate, da es vermutlich nicht immer
ints sind.
Und wenn du drei Variablen "resetten" willst, dann erzeugst du lokal halt drei Instanzen dieser Klasse.