2009-05-11 15 views
15

C++で書かれたいくつかの機能のC APIを開発しており、エクスポートされたC関数から例外が伝播しないようにしたいと考えています。例外処理でのコード再利用

それを行うための簡単な方法は、それぞれのエクスポートされた関数が中に含まれていることを確認作っている:

try { 
    // Do the actual code 
} catch (...) { 
    return ERROR_UNHANDLED_EXCEPTION; 
} 

はのは、私はしばしばC++コード内で逃している唯一の例外は、STDである知っているとしましょう:: bad_allocと私がしたいですそれを処理するために特別に私の代わりにこのような何かを書きたい:

try { 
    // Run the actual code 
} catch (std::bad_alloc& e) { 
    return ERROR_BAD_ALLOC; 
} catch (...) { 
    return ERROR_UNHANDLED_EXCEPTION; 
} 

は私が世界的に周りの例外ハンドラのための新たなcatchステートメントを追加することなく、異なるいくつかのエラーを処理することができるようにいくつかの巧妙な方法でこれを分解することが可能ですすべてのエクスポートされた関数?

これはプリプロセッサを使って解決することが可能ですが、その道を行く前に、私はそれを行う方法が他にないことを確認したいと思います。

答えて

27

エクスポートされた関数:

try 
{ 
    ... 
} 
catch(...) 
{ 
    return HandleException(); 
} 
+1

+1:良いアイデア:-) –

+0

完全に作業しました。ありがとう! – Laserallan

+2

実際のコードでは、例外によって例外をキャッチすることを忘れないでください:catch(std :: bad_alloc&) – Jem

0

多かれ少なかれ再投げを計画していない限り、catch(...)を使用しないでください。あなたは確かに、あなたがエラーの原因を理解するのに役立つエラー情報を失います。

私はあなたのコードが投げる唯一のものであり、残りの部分を残すことができるため、例外の既知のセットをキャッチして、少し上手くいくのが好きです。アプリがクラッシュする可能性はおそらく最高ですあなたが未知の行動を引き起こしたので、「責任を負う」ことが最善です。

何について
+4

この場合、catch(...)の使用が正しいと思います。C++では、投げることができるすべての例外を予測することは、不可能ではないにしても難しいですが、Cコードに伝播するのを防ぐ必要があります。 –

+0

これを実行すると、問題の原因と何も起こらない方法に関する情報がほとんどない、悪いバグレポートの入力を計画しています –

+0

だから、むしろプログラムがクラッシュするのは、2つの削除するとMyWeirdErrorがスローされますか?私はむしろ、ログに "操作XXXの未確認の問題"があると思います。 –

1

int HandleException() 
{ 
    try 
    { 
     throw; 
    } 

    // TODO: add more types of exceptions 

    catch(std::bad_alloc &) 
    { 
     return ERROR_BAD_ALLOC; 
    } 
    catch(...) 
    { 
     return ERROR_UNHANDLED_EXCEPTION; 
    } 
} 

そして、それぞれの中:あなたは以下のように、すべての可能な例外が1つだけハンドラ関数を使用し、それぞれたり、APIの実装関数からそれを呼び出すことができます

try{ 
    //Your code here 
} catch(std::exception e) 
{ 
    return translateExceptionToErrorCode(e); 
} catch(...) 
{ 
    return UNKNOWN_EXCEPTION_THROWN; 
} 
+2

通常、不要なコピーを避けるために、参照によって例外をキャッチします。 –

+3

スライシングはもちろんのこと、 –

+0

非常に良い点があります。私のコードを擬似的に扱う; – PaulJWilliams

0

言語boでエラー情報を緩和するのは残念です一族。すべての例外をCから使用可能なエラーコードに変換しようとするべきです。

どのように行うかは、例外クラスの外観によって異なります。例外クラス階層を制御する場合は、各クラスが仮想メソッドを使用して翻訳を提供できるようにすることができます。そうでない場合は、トランスレータ関数を使用し、Jemが示唆したようにエラーコードに変換するために受け取った 'std :: exception'の派生例外の型をテストすることが現実的かもしれません(覚えておいてください:パフォーマンスはとにかく、翻訳が遅くなることを心配しないでください)。

+3

例外をエラーコードに変換することは、彼がやっていることとまったく同じようです! –

1

Jem答えはこの解決策よりも少し簡単です。しかし、プリプロセッサマクロの使用をテンプレートの使用で置き換えることは可能です。このようなもの(より洗練されたもの):

template <class T, void (T::*FUNC)()> 
class CatchWrapper 
{ 
public: 

    static void WrapCall(T* instance) 
    { 
     try 
     { 
      (instance->*FUNC)(); 
     } 
     catch (std::bad_alloc&) 
     { 
      // Do Something 1 
     } 
     catch (std::exception& e) 
     { 
      // Do Something 2 
     } 
     catch (...) 
     { 
      // Do Something 3 
     } 
    } 
}; 


class Foo 
{ 
public: 
    void SomeCall() 
    { 
     std::cout << "Do Something" << std::endl; 
    } 
}; 


int main(int argc, char* argv[]) 
{ 
    Foo i; 
    CatchWrapper<Foo, &Foo::SomeCall>::WrapCall(&i); 
    return 0; 
} 
+0

これは私が最初にやったことです(そして私のプロジェクトのいくつかで実際に使ったことです)。しかし、Jemのアンカーは私の立場から見るときれいです。それは私を邪魔しないが、時にはテンプレートは他のプログラマーを邪魔する。:/ –

4

既に良い答えがあります。しかし、FYIは、例外的なディスパッチャーのイディオムと呼ばれています。C++ FAQ 17.15を参照してください。 IMHO 17.16も重要な読書です。

+0

ありがとう、これは素晴らしい読書だった。 – Laserallan

+0

今[17.15] [http://www.parashift.com/c%2B%2B-faq-lite/throw-without-an-object.html] – baruch

+0

@baruch:ありがとう、新しいURLに修正されました。 – Abhay