Einer meiner Freunde hat mich angesprochen. Ich steckte fest, weil ich nicht in der Lage bin, Ausnahmen zu benutzen. Denken Sie daran, dass wir beide in einer Arbeitsumgebung arbeiten, in der wir C ++ verwenden, aber die Fehlerbehandlung in C-Tradition durchführen. Sein Problem war in etwa so:
Funktion A
ruft B
auf, was wiederum C
aufruft. Eine Ausnahme wird von C
ausgelöst, und der catch-Block für diese Ausnahme befindet sich in A
. Was passiert mit Ressourcen, die in B
vor dem Aufruf von C
erworben wurden? Wie säubern wir diese? Meine Antwort war Verwendung RAII. Aber selbst als ich es sagte, wusste ich, dass es nicht funktionieren würde. Wir haben riesige Codebasen, die im C-Modus geschrieben wurden. Nirgends im Code habe ich Autozeiger und so gesehen. Ressourcen sind nicht unbedingt in Klassen eingepackt. Selbst wenn sie es sind, bleiben die Destruktoren in den meisten Fällen für den Compiler übrig. Kurz gesagt, alles wird manuell erledigt.
Das eigentliche Problem ist, was zu tun ist, um den Übergang von der C-Fehlerbehandlung zu Ausnahmen mit dem Gewicht einer riesigen Codebasis zu machen? Das von meinem Freund gestellte Problem ist nur eine der möglichen Fragen, die aufgeworfen werden können, wenn Sie mit der C-Fehlerbehandlung vertraut sind und wissen möchten, wie die Migration von dort zu Ausnahmen erfolgen kann.
Es gibt eine Technik, die von Andrei Alexandrescu und Joshua Lehrer entwickelt wurde und Scope Guard genannt wird und eine Technik für Bereitstellen eines "Scope-Exit" -Codes, sobald Sie ein Objekt zuweisen und an diesem Punkt den Bereich dafür öffnen.
Die Programmiersprache D hat es eigentlich als Standard.
boost libraries hat eine Erweiterung namens Scope Exit . Wenn Ihr Code nicht ausnahmesicher ist, funktioniert die Funktion B nicht, sie wird nicht korrekt behandelt, wenn etwas ausgelöst wird.
Destruktoren werden beim Abwickeln des Call-Stacks nach einer Exception ausgeführt. Deshalb müssen Sie sicherstellen, dass sie selbst keine Ausnahmen auslösen.
Das eigentliche Problem ist, was zu tun ist, um den Übergang von C-Fehlerbehandlung zu Ausnahmen mit dem Gewicht einer riesigen Codebasis zu machen?
Nein, das eigentliche Problem ist, dass Sie, da Sie in C ++ programmieren, längst damit fertig sein sollten. Selbst wenn Ihr eigener Code keine Exceptions auslöst, könnte ein Code in die Standardbibliothek und das Laufzeitsystem werfen ( new
, dynamic_cast
) und natürlich alle Software von Drittanbietern, die Sie verwenden könnten, war gut.
Ich stimme zu, dass Scope Guard wahrscheinlich die beste Option ist, die Ausnahmesicherheit nachträglich hinzuzufügen. Täuschen Sie sich jedoch nicht, indem Sie denken, dass Sie das nicht tun müssen, solange Sie keine Ausnahmen selbst auslösen. Sie verwenden eine Sprache mit Ausnahmen . Beginnen Sie also so schnell wie möglich damit.
C ++ Unterstützt finally nicht, um Last-Minute-Zeug am Ende des Blocks zu verwalten.
Wenn die Funktion C eine Ausnahme auslöst, wird sie von der Funktion zurückgegeben. Das bedeutet, dass alle lokalen Variablen zerstört werden.
Dann kehrt das Programm zu dem Code in B zurück, es wird nach einem catch-Block suchen, es wird auf non geachtet und zurück zu Funktion A. Wieder werden alle lokalen Variablen in B freigegeben.
Sie müssen sich daran erinnern, dass Sie in C ++ arbeiten. Sie müssen Ihre Objekte verwalten. Wenn Sie also Objekte haben, die sich in B (mit Zeigern oder was auch immer) frei bewegen, dann ist das ein schlechter Codeentwurf, und sie werden nicht veröffentlicht.
Wenn Sie in B wissen, dass in C eine Ausnahme vorhanden sein könnte, können Sie einfach einen Haken setzen und dann die gefangene Ausnahme zurückwerfen.
> Der nächste Block, den du erreichen kannst, benutzt finally
und benutzt ihn, um Speicher freizugeben ... aber er wird nur eingegeben, wenn es tatsächlich eine Ausnahme gab, also ist es nicht identisch mit catch(...)
Wenn Sie genau wie ein finally
-Block arbeiten möchten, können Sie Folgendes tun:
Für alle, die ein Problem mit finally
... haben, ist es immer noch ein Befehl und dies ist ein perfektes Beispiel dafür, dass goto
oder break
oder eine Inline-Funktion continue
ersetzen kann.
Etwas mehr über goto
Ein Auszug von meiner verlassenen Homepage ...
Ohne im Detail alles zu wiederholen Probleme, die der Ausnahme innewohnen Handhabung (1) Ich möchte nur die Hauptidee: Der komplexe Teil ist nicht wo die Ausnahme generiert wird (werfen) oder wo die Ausnahme ist gehandhabt (fangen) aber in den Methoden von alle Klassen, die die Ausnahme übergibt fast asynchron während der Stapelabwickelprozess.
Achten Sie auf Methoden geschrieben werden ist relativ einfach zu vermeiden Ressourcen verlieren im Falle von Ausnahmen (Verwendung von auto_ptr und ähnlichen Klassen) aber die Dinge sind viel komplexer als man berücksichtigt den logischen Zustand des Objekts oder anderer Objekte vor dem Wurf manipuliert. In dem strengste Bedeutung von Ausnahme-Safe Eine Methode sollte entweder erfolgreich sein oder ein No-Op sein: mit anderen Worten die logischer Zustand des aufgerufenen Objekts (und andere involvierte Objekte) sollten sein das gleiche, wenn eine Ausnahme ausgelöst wird: nein Unterschied sollte durch sichtbar sein die öffentliche Schnittstelle aller Beteiligten Klassen.
...
(1) Für eine ausführliche Beschreibung lesen Sie die Artikel "Ausnahmebehandlung: Ein Falsch Sinn für Sicherheit "von Tom Cargill verfügbar online oder das Interessante Sammlung von Problemen / Lösungen, die Dieser Artikel wurde auf USENET generiert verfügbar auf dem Buch "Außergewöhnlich C ++ "von Herb Sutter ISBN = 0-201-61562-2.
Sei froh, dass du Ausnahmen hast. Überlegen Sie, was mit den Fehlerrückgabecodes in Ihrem Beispiel passiert. Die Funktion C
gibt einen Fehlercode zurück. B
, naiv wie es ist, schluckt es. Anrufer A
, der in der Lage wäre, damit umzugehen, wird nicht einmal über den Fehler informiert.
Am besten gehen Sie von C direkt nach C ++ 0x. Es bietet eine neue Funktion, Lambda's. Dies sind anonyme Funktionen, die in anderen Funktionen definiert sind. Sie können Ihren C-Cleanup-Code dort eingeben und ihn von einem "Scopeguard" -Objekt aufrufen lassen. Beispiel (Ich würde das Makro überspringen)
Tags und Links c++ error-handling exception