Ich frage nicht, ob es sicher ist, dass eine C ++ - Ausnahme durch C-Code verbreitet wird, oder was passiert, wenn so etwas passiert. Ich habe die folgenden Fragen in SO gelesen ( 1 , < a href="https://stackoverflow.com/questions/6426835/what-happens-if-exception-gets-thrown-through-c-code"> 2 , 3 ) und diese FAQ . Ich frage, wie es weitergeht mit:
Lassen Sie mich meine Idee veranschaulichen:
Sage libfoo
ist eine C-Bibliothek, die ich in meinem bar
C ++ Programm verwenden möchte. libfoo
benötigt eine Callback-Funktion foo_callback
, die ich bereitstellen muss. Die Funktionen und Methoden, die in meinem Rückruf verwendet werden, können eine Ausnahme auslösen, also schrieb ich:
Und dann verwende ich meinen Rückruf wie folgt:
%Vor% Was ich will, ist, dass ich die Ausnahmen von my_callback
in der Funktion main
abfangen kann, ohne dass sich die Ausnahme durch libfoo
ausbreitet (Ja, es ist eine Art Quantenausnahme, die experimentiert Quantum Tunneling durch C-Code).
Also der Code, den ich gerne verwenden würde:
%Vor%Angesichts der folgenden Einschränkungen:
libfoo
ist quellengeschlossen, in C geschrieben und im kompilierten Format von einem Anbieter bereitgestellt. In der Bibliothek durchgeführte Tests haben gezeigt, dass sich Ausnahmen nicht durchsetzen können. Ich habe weder Zugriff auf die Quelldateien, noch kann ich eine kompilierte Version erhalten, die Ausnahmen unterstützt. Meine Fragen:
boost
) oder gar c ++ 0x? Vielen Dank für einen Rat!
BEARBEITEN: Ich habe eine Antwort mit einer kleinen Implementierung des Mechanismus zum Halten / Freigeben von Ausnahmen hinzugefügt. Alle Kritiker oder Vorschläge sind willkommen.
Bearbeiten: Sie können fungo verwenden, eine bessere Umsetzung der Idee, die ich unten beschrieben habe. Von seinem Autor:
fungo ist eine C ++ - Bibliothek, die für diejenigen von uns entwickelt wurde, die mit älteren C ++ - Implementierungen arbeiten, die dies tun unterstützt noch nicht std :: exception_ptr.
Mit anderen Worten: Mit fungo können Sie einen fairen Versuch machen, Ausnahmen zu speichern und später erneut zu werfen, die von einem Fangblock (...) erfasst wurden. Dies ist nützlich, um Ausnahmen über Thread-Joins oder über C / C ++ - Grenzschnittstellen zu verbreiten.
Ich werde dies als eine Antwort markieren.
Wie ich in meiner Frage erwähnt habe, kann ich C ++ 0x / 11 Funktionen für jetzt nicht verwenden (neue Funktionen sind nicht geplant), und ich werde hier vorstellen, was ich bisher gemacht habe:
Ausnahmen haben eine Lebensdauer, die sich über den Try-Catcher-Block erstreckt. Um speichern eine Ausnahme zu speichern, muss eine Kopie auf dem Heap erstellt werden. Wir entfernen die Kopie, wenn wir die Ausnahme erneut werfen. Ich habe eine Ausnahme-Halter Schnittstelle geschrieben:
%Vor%Dies ist eine typunabhängige Klasse. Der Ausnahmetyp wird mithilfe von Vorlagen eingeführt:
%Vor%Ich habe eine Reihe von Tests / Optimierungen / Überprüfungen entfernt, ich habe die Hauptidee beibehalten. Bisher haben wir einen Ausnahmebehälter für einen Typ, so dass wir einen Ausnahmespeicher erstellen können, der viele Typen gleichzeitig speichern kann.
%Vor%Ich kann den Ausnahme-Speicher wie folgt verwenden:
%Vor% Dies ist sehr einfach und es könnte einige unerwartete Szenarien geben, die in diesem Beispiel nicht behandelt werden. Wenn eine Ausnahme mit einem Typ, der nicht mit AddExceptionHolder
deklariert ist, throw ist, haben Sie zwei Möglichkeiten:
Für den Moment bevorzuge ich diese Lösung zu der mehr getestet / verwendet / verifiziert boost :: enable_current_exception , weil ich es mir nicht leisten kann, den gesamten C ++ - Code so umzuformen, dass alle Werbeseiten mit boost::enable_current_exception(...)
umgeben sind.
Wie auch immer, die std::exception_ptr
scheint die perfekte Lösung zu sein, und ich werde den obigen Code ersetzen, sobald ich zum neuen C ++ - Standard übergehen kann.
Ich glaube, dass boost.exception einen Mechanismus hat, der angepasst werden könnte, um für Ihren Zweck nützlich zu sein. Siehe hier zur Inspiration:
Es scheint so zu sein, dass sie ihren speziellen Ausnahmetyp zwischen Threads kommunizieren soll, aber ich denke, es ist so ziemlich dasselbe - haltet eine Ausnahme davon ab, sich über die Threadgrenze oder C-Codegrenze hinaus zu verbreiten, eine Kopie davon hinter a Zeiger, dann abrufen Sie es später über den Zeiger auf der anderen Seite der Grenze und optional erneut zu lösen.
Ich bin mir nicht sicher, wie machbar es ist, Ihre eigenen Exceptions von Boos magischem Exceptionstypen ableiten zu lassen, aber wenn ich mich daran erinnere, dass ich vor ungefähr einem Jahr richtig damit herumgespielt habe, ist das ziemlich vernünftig.
In c ++ 11 können Sie current_exception () in Ihrem Callback verwenden, um eine Variable vom Typ exception_ptr zu setzen, und wenn Ihr aufrufender Code von der Bibliothek über den Fehler informiert wird, verwenden Sie rethow_exception ().
Dies ist derselbe Mechanismus, der verwendet wird, um Ausnahmen über Threads in C ++ 0x zu propagieren.
Beispiel:
%Vor%Wenn Sie keinen großen Refactor haben, können Sie eine bestimmte Untergruppe von Exceptionstypen identifizieren, die möglicherweise ausgelöst werden?
Wenn dies der Fall ist, können Sie wahrscheinlich einen Container schreiben, um Kopien von jedem einzelnen zu speichern, und diese dann bei der Rückkehr vom C-Aufruf abrufen. Dazu muss der Ausnahmetyp kopiert werden können.
Betrachten Sie alternativ die endgültige Auflösung der verschiedenen Ausnahmen (falls möglich) und packen Sie diese in ein Objekt, das bei der Rückgabe verarbeitet werden soll. Dies funktioniert nur, wenn Sie genug von der Codebasis besitzen, um zu wissen, welche potentielle Handhabung die Ausnahmen erzeugen können.
Ein Hybridmodell würde die Ausnahmen abfangen, eine neue Ausnahme basierend auf dem Gefundenen erstellen und diese dann bei der Rückkehr aus der C lib werfen.