5

C++ で扱っている 2 つの継承階層があるとします。1 つはstd::exception(新しい階層)から継承し、もう 1 つはException(従来の C++ Builder VCL 基本例外クラス) から継承します。いずれかのタイプの例外をスローする可能性のあるコードを呼び出す場合、次のようなコードを記述する必要があります。

try {
    // do stuff....
    Function1();
    Function2();
} catch (std::exception &ex) {
    std::cout << "STL exception caught: " << ex.what() << std::endl;
} catch (Exception &ex) {
    std::cout << "Legacy exception caught: " << ex.Message.c_str() << std::endl;
} catch (SomeOtherVendorLibraryException &ex) {
    // etc.
}

問題は、C++ には catch-all として使用できる真の強制例外基本クラスがないため、各呼び出し元が最後のすべてのタイプの例外を取得しようとするためにこれらすべての catch 句を持っている必要があることです (例: System.ExceptionC# のクラス)。(catch (...)何をキャッチしたかを知る方法がなく、アクセス違反などの危険なシステム例外もキャッチされる可能性があるため、これはスターターではありません。トラップしない方がよいでしょう。)

これらの「レガシー」例外を階層内のクラスにラップしたいと思いstd::exceptionます。サードパーティの例外を独自の例外システムにラップするというこの概念は、まったく前例のないものではありません。たとえば、.NET Framework は、他のシステム (例: COMException) の広範なエラー セットをラップします。理想的には、次のようなものを見たいと思っています。

class LegacyException : public std::runtime_error {
public:
    // construct STL exception from legacy exception
    LegacyException(const Exception &ex) : std::runtime_error(ex.Message.c_str()) {}
};

try {
    // In reality, this throw will happen in some function we have no control over.
    throw Exception("Throwing legacy exception!");
} catch (std::exception &ex) {
    // Ideally, the compiler would use the LegacyException constructor
    // to cast the thrown Exception to a LegacyException, which ultimately
    // inherits from std::exception.
    std::cout << ex.what() << std::endl;
}

当然のことながら、例外がキャッチされることはありません。例外をキャッチするために、コンパイラにかなりの魔法を要求することになります。

レガシー例外をラップするために上記に似たソリューションがあり、これらの目標を達成できますか?

  • 1 つの "catch" 句または類似の句。これにより、一般的な例外処理ロジックを 1 回記述するだけで済みます。
  • ある例外タイプから別の例外タイプに変換するためのロジックを集中化する必要があります。
  • 可能であればマクロを避けます。
  • ラムダ関数は使用しません。
4

1 に答える 1

2

BC++Builder を使用して同じ問題に遭遇しましたが、当時はマクロが唯一の解決策のようでした。

「よりクリーンな」(うーん...) 解決策は、おそらく「二重の try-catch」です。内側の try-catch がレガシー例外を標準クラスに変換し、外側の try-catch が実際に例外を処理します。

私は手元にコードを持っていません(何年も経っています)が、基本的には次のようになります。

#define DTRY  try { try
#define DCATCH catch (Exception& e) { throw LegacyException(e); } } catch

DTRY {
   ...
}
DCATCH(std::exception& e) {
    // handle the exception
}

はい、それが醜いことは知っていますが、Borland と一緒に仕事をしたとき、これ以上のものは見つかりませんでした。事実、当時、Borland は非常に非標準的であり、その後どのように進化したかはわかりませんが、今日ではもっとうまくできるかもしれません。とにかくこれが役立つことを願っています。

于 2013-03-28T22:01:32.417 に答える