2009-05-27 8 views
4

Ich verwende swig, um eine Klasse aus einer C++ - Bibliothek mit Python zu umhüllen. Es funktioniert insgesamt, aber es gibt eine Ausnahme, die aus der Bibliothek geworfen wird, und ich kann nicht scheinen, es in der swig-Schnittstelle zu fangen, so stürzt es nur die Python-Anwendung ab!Keine Ausnahme möglich!

Die Klasse PyMonitor.cc beschreibt die Swig-Schnittstelle zur gewünschten Klasse, Monitor. Der Monitor-Konstruktor löst eine Ausnahme aus, wenn keine Verbindung hergestellt werden kann. Ich mag diese Ausnahme in PyMonitor zu handhaben, zB:

PyMonitor.cc:

#include "Monitor.h" 

// ... 

bool PyMonitor::connect() { 
    try { 
     _monitor = new Monitor(_host, _calibration); 
    } catch (...) { 
     printf("oops!\n"); 
    } 
} 

// ... 

jedoch die Methode connect() fängt nie die Ausnahme, bekomme ich nur ein „nach dem Werfen genannt beenden. .. "Fehler, und das Programm bricht ab.

Ich weiß nicht zu viel über swig, aber es scheint mir, dass dies alles in Ordnung C++ ist und die Ausnahme sollte die connect() -Methode propagieren, bevor das Programm zu töten.

Irgendwelche Gedanken?

+1

Sind Sie sicher, dass Ihre Verbindungsmethode überhaupt eingegeben wurde? Sie können Ihren Code debuggen und ihn im Debugger einzeln ausführen. Das sollte dir zeigen, wo das Problem liegt. – lothar

+0

Ja, die connect-Methode ist definitiv eingegeben, ich habe sie im obigen Code weggelassen, aber es gibt printf's und fflush (stdout) 's im try-Block vor und nach der Zuweisung zu _monitor. Die vorherige wird gedruckt, aber die Exception wird vom Monitor-Konstruktor ausgegeben und es gibt keine Ausgabe von der zweiten. Bezüglich Debugging, haben Sie irgendwelche Hinweise dafür? Da der eigentliche Python-Code diese Methoden aufruft, weiß ich in diesem Fall nicht viel über Debugging. Funktionieren die grundlegenden gdb-Tricks? – chase

+0

Vielleicht fängt der Monitor-Konstruktor die Ausnahme ab und beendet die Laufzeit intern ...? – harto

Antwort

1

Ich bin nicht vertraut mit SWIG, oder mit C++ und Python zusammen, aber wenn dies unter einer aktuellen Version von Microsoft Visual C++ ist, wirft die Monitor Klasse wahrscheinlich eine C-strukturierte Ausnahme, anstatt ein C++ - Typ Ausnahme. C-strukturierte Ausnahmen werden nicht von C++ - Ausnahmehandlern abgefangen, auch nicht von catch(...). Wenn das der Fall ist, können Sie die Schlüsselwörter __try/__except (anstelle von try/catch) verwenden oder die _set_se_translator-Funktion verwenden, um die C-strukturierte Ausnahme in eine C++ - typisierte Ausnahme zu übersetzen. Gehen Sie hierzu folgendermaßen vor: .

(Ältere Versionen von MSVC++ behandelt C strukturierte Ausnahmen wie C++ int Typen und sind von C++ Handler gefangen, wenn ich mich richtig erinnere.)

Wenn diese nicht unter Microsoft Visual C++, dann Ich bin mir nicht sicher, wie das passieren könnte.

EDIT: Da Sie sagen, dass dies nicht MSVC ist, fängt vielleicht etwas anderes die Ausnahme (und das Programm beenden), bevor Ihr Code es bekommt, oder vielleicht gibt es etwas in Ihrem catch-Block, der eine weitere Ausnahme auslöst? Ohne weitere Einzelheiten, mit denen ich arbeiten kann, sind das die einzigen Fälle, die ich mir vorstellen kann, die diese Symptome verursachen würden.

+0

Entschuldigung, ich hätte angeben sollen, ich benutze nur die gnu toolchain, nicht MVC++. Die Ausnahme, die von Monitor ausgelöst wird, ist eine übliche C++ - Ausnahme, die das Schlüsselwort throw für ein C++ - Objekt verwendet. – chase

1

Es ist möglich, dass eine Funktion direkt oder indirekt vom Monitor constructor genannt wird seine Ausnahmespezifikation verletzt und nicht std::bad_exception erlaubt geworfen werden. Wenn Sie die Standardfunktion zum Überfüllen nicht ersetzt haben, würde dies das Verhalten erklären, das Sie sehen.

Um diese Hypothese zu testen, Sie könnten versuchen, Ihren eigenen Handler definieren: „Schlimme Dinge passieren“

void my_unexpected() 
{ 
    std::cerr << "Bad things have happened!\n"; 
    std::terminate(); 
} 


bool PyMonitor::connect() { 

    std::set_unexpected(my_unexpected); 

    try { 
     _monitor = new Monitor(_host, _calibration); 
    } catch (...) { 
     printf("oops!\n"); 
    } 
} 

Wenn Sie das bekommen Fehlermeldung, dann haben Sie bestätigt, dass dies der Fall ist, aber leider kann es nicht viel geben, was Sie tun können. Wenn Sie Glück haben, können Sie möglicherweise eine Ausnahme von my_unexpected auslösen, die durch die Ausnahmebedingung der Funktion, die derzeit fehlschlägt, zulässig ist. In jedem Fall darf Ihr unerwarteter Handler jedoch nicht normal beendet werden. Es muss werfen oder anderweitig enden.

Um dies zu beheben, müssen Sie wirklich in den aufgerufenen Code gelangen und ihn entweder korrigieren, so dass die Ausnahmespezifikation nicht verletzt wird, indem Sie entweder die Spezifikation selbst korrigieren oder den Code so festlegen, dass die Ausnahme nicht ausgelöst wird wird nicht erwartet.

Eine andere Möglichkeit besteht darin, dass während des Abwickelns des Stacks eine Exception ausgelöst wird, die durch das Auslösen der ursprünglichen Exception verursacht wird. Dies würde auch die Beendigung des Prozesses verursachen. In diesem Fall haben Sie zwar die Möglichkeit, die Standard-Terminierungsfunktion zu ersetzen, aber Sie haben keine andere Wahl, als das Programm abzubrechen. Ein Abbruch-Handler darf weder werfen noch zurückgeben, er muss das Programm beenden.

+0

Das ist eine interessante Idee. Ich habe versucht mit set_unexpected wie oben, und ich konnte es nicht fangen. Als ich jedoch etwas Ähnliches mit set_terminate versuchte, konnte ich wieder etwas Kontrolle gewinnen, indem ich nur eine Nachricht ausgab und einen Abbruch anrief. Ich beginne zu glauben, dass sig PyMonitor und Monitor irgendwie in verschiedenen Prozessräumen laufen lässt, und die Ausnahme, die im Monitor-Konstruktor ausgelöst wird, rollt irgendwie an die Spitze ihres Stapels, bevor sie in PyMonitor kommt. Ist das möglich? – chase

4

Sie müssen die Ausnahmen an Python weiterleiten, wenn Sie sie dort analysieren wollen. Siehe SWIG Documentation. Um Ausnahmen weiterzuleiten, müssen Sie nur etwas Code in der SWIG-Schnittstelle (.i) hinzufügen. Grundsätzlich kann dies überall in der .i-Datei sein.

Alle Arten von Ausnahmen sollten nur Fänge die aufgeführten Ausnahmetypen (in diesem Fall std :: runtime_error, std :: invalid_argument, std :: out_of_range), alle anderen Ausnahmen sind gefangen wie hier unbekannt, und SWIG angegeben werden Ausnahmen (und werden somit korrekt weitergeleitet!).

// Handle standard exceptions. 
// NOTE: needs to be before the %import! 
%include "exception.i" 
%exception 
{ 
try 
{ 
    $action 
} 
catch (const std::runtime_error& e) { 
    SWIG_exception(SWIG_RuntimeError, e.what()); 
} 
catch (const std::invalid_argument& e) { 
    SWIG_exception(SWIG_ValueError, e.what()); 
} 
catch (const std::out_of_range& e) { 
    SWIG_exception(SWIG_IndexError, e.what()); 
} 
catch (...) { 
    SWIG_exception(SWIG_RuntimeError, "unknown exception"); 
} 
} 
Verwandte Themen