Ein Mechanismus, um die Ausnahmeausbreitung beim Mischen von C- und C ++ - Code zu gewährleisten

8

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:

  • Vermeiden Sie es, irgendeine C ++ - Exception in Richtung C-Code zu leasen (dies bedeutet, dass alle Exceptions im C ++ - Land vor dem Aufruf des C-Codes abgefangen werden)
  • Kann auch die Ausnahmen außerhalb des C-Codes (in einem höheren C ++ - Code) abfangen.

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:

%Vor%

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.
  • Die Callback-Funktion verwendet häufig C ++ - Code, der Ausnahmen verwendet. Die gesamte Fehlerbehandlung basiert auf dem Ausnahmemechanismus. In keiner Weise kann ich einfach den Code verwenden, der alle Ausnahmen verschluckt.
  • Kein Multithreading involviert.
  • Keine C ++ 0x Unterstützung.

Meine Fragen:

  • Ist es bereits von einer Bibliothek oder einer C ++ - Magie (wie boost ) oder gar c ++ 0x?
  • gelöst?
  • Wenn nicht, wie kann ich einen ExceptionHolder schreiben, der mit einem beliebigen Ausnahmetyp funktioniert? Ich bin confortable mit C ++, aber ich habe keine Möglichkeit gefunden, einen zuverlässigen und einfach zu verwendenden ExceptionHolder zu schreiben, der mit jedem Ausnahmetyp funktioniert.

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.

    
overcoder 15.10.2011, 23:21
quelle

4 Antworten

1

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:

  • Ein Halter für einen Basistyp wird dem Geschäft hinzugefügt, sodass die Ausnahme abgefangen und in Scheiben geschnitten wird, wobei nur eine Kopie des Basistyps beibehalten wird.
  • Kein Halter passt zur Ausnahme und er ist einfach verloren. Nichts leckt in das C Land.

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.

    
overcoder 19.10.2011, 19:47
quelle
4

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.

    
ben 16.10.2011 00:48
quelle
2

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%     
bames53 18.10.2011 05:53
quelle
1

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.

    
Keith 17.10.2011 05:39
quelle

Tags und Links