2009-05-27 30 views
4

私は、pythonでC++ライブラリからクラスをラップするためにswigを使用しています。それは全体的に機能しますが、ライブラリ内から例外がスローされ、swigインターフェイスでそれをキャッチしているように見えないので、Pythonアプリケーションがクラッシュします。例外をキャッチできません!

PyMonitor.ccクラスは、希望のクラスMonitorに対するswigインターフェイスを記述します。 接続に失敗した場合、Monitorのコンストラクタは例外をスローします。私は、例えば、PyMonitorでこの例外を処理したいと思います:

PyMonitor.cc:

#include "Monitor.h" 

// ... 

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

// ... 

しかし、connect()メソッドが例外をキャッチすることはありません、私はちょうど「投げた後に呼び出さ終了します。 .. "エラーが発生し、プログラムが異常終了します。

私はswigについてあまり知りませんが、これはすべて素晴らしいC++であり、例外はプログラムを強制終了する前にconnect()メソッドに伝播する必要があります。

どのような考えですか?

+1

接続方法はまったく入力してもよろしいですか?あなたのコードをデバッグし、デバッガでそれを一歩進めることができます。それは問題がどこにあるかを示すはずです。 – lothar

+0

はい、connectメソッドは間違いなく入力されていますが、上記のコードでは省略しましたが、_monitorへの代入の前後にtryブロックにprintfとfflush(stdout)があります。以前のものが出力されますが、例外はMonitorのコンストラクタによってスローされ、2番目の出力は出力されません。 デバッグに関しては、これについての指針はありますか?実際にはこれらのメソッドを呼び出すPythonコード以来、私はこの場合のデバッグについてあまり知らないです。基本的なgdbトリックは機能しますか? – chase

+0

おそらく、Monitorコンストラクタが例外をキャッチし、内部的にランタイムを終了します...? – harto

答えて

1

私はswigやC++とPythonを一緒に使うのに慣れていませんが、Microsoft Visual C++の最近のバージョンの下では、MonitorクラスはおそらくC++型ではなくC構造化例外をスローしています例外。 C構造化例外は、C++例外ハンドラによって捕捉されず、catch(...)でもあります。

この場合、try/catchの代わりに__try/__exceptキーワードを使用するか、_set_se_translator関数を使用してC構造化例外をC++型付き例外に変換できます。その後、

(MSVC++の古いバージョンでは、C++ intタイプとしてC構造化例外を処理する、と私は記憶が正しければは、C++ハンドラによってをキャッチされている。)

このは、Microsoft Visual Cの++の下でない場合には、どのように起こっているのか分かりません。

EDIT:これはMSVCではないと言われているので、あなたのコードがそれを取得する前に他の何かが例外をキャッチしている(そしてプログラムを終了している)かもしれません。より詳細な情報がなければ、それらの症状を引き起こすと考えられる唯一のケースです。

+0

申し訳ありませんが、指定する必要があります。MVC++ではなく、gnuツールチェーンを使用しています。 Monitorからスローされる例外は、C++オブジェクトでthrowキーワードを使用する通常のC++例外です。 – chase

1

モニタconstructorによって直接的または間接的に呼び出された関数が例外仕様に違反しており、std::bad_exceptionをスローすることができない可能性があります。これをトラップするための標準関数を置き換えていない場合、それはあなたが見ている動作を説明するでしょう。この仮説を検証するために

独自のハンドラを定義試みることができる:「!悪いことが起こっている」あなたが得る場合

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"); 
    } 
} 

をエラーメッセージが表示された場合、これが該当することを確認しましたが、残念ながらあなたができることはあまりないかもしれません。あなたが '運が良ければ' my_unexpectedから、現在失敗している関数の例外仕様で許可されている例外をスローすることができるかもしれませんが、予期せぬハンドラが正常に終了することはできません。それは投げたり、そうでなければ終了しなければならない。

これを修正するには、実際に呼び出されたコードに入り、例外仕様に違反しないように修正するか、仕様自体を修正するか、例外をスローしないようにコードを修正します。期待されていません。

もう1つの可能性は、元の例外がスローされたことによるスタックの巻き戻し中に例外がスローされていることです。これにより、プロセスが終了することもあります。この場合、標準の終了関数を置き換えることはできますが、プログラムを中止することはできません。終了ハンドラはスローまたはリターンすることはできません。プログラムを終了する必要があります。

+0

それは興味深い考えです。私は上記のようにset_unexpectedを使ってみましたが、それを捕まえることができませんでした。しかし、set_terminateと似たようなことを試したときに、メッセージを出力して中止を呼び出すだけで、もう一度何らかの制御を得ることができました。 私はswigが何らかの理由でPyMonitorとMonitorを別のプロセス空間などで実行させていると思っています.Monitorコンストラクタでスローされた例外は、何とかPyMonitorに入る前にスタックの先頭に戻ってきます。これは可能ですか? – chase

4

例外を解析するには、例外をPythonに転送する必要があります。 SWIG Documentationを参照してください。 例外を転送するには、SWIGインターフェイス(.i)ファイルにコードを追加するだけです。基本的に、これは.iファイルのどこにでも置くことができます。

例外のすべての種類は、ここで指定しなければならない、とSWIG のみキャッチ上場の例外タイプを(この場合はstd :: runtime_error、STD ::例外Invalid_argument、STD :: out_of_rangeに)、他のすべての例外は、未知のものとして捉えています例外が発生します(したがって、正しく転送されます)。

// 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"); 
} 
} 
関連する問題