web-dev-qa-db-ja.com

std :: exceptionから派生/継承する必要がありますか?

私の最初の「深刻な」C++ライブラリを設計するとき、私は自分自身に尋ねています。

_std::exception_から例外を派生させるのは良いスタイルですか?それは子孫ですか?

読んでも

まだわかりません。一般的な(ただし多分良いとは言えない)プラクティスに加えて、ライブラリユーザーは、ライブラリ関数が_std::exception_ sをスローするのは、標準のライブラリ関数がライブラリの実装で失敗し、何もできないと想定するためです。それについて。しかし、それでも、アプリケーションコードを作成する場合、私にとっては非常に便利です。また、_std::runtime_error_をスローするだけで見栄えも良いです。また、私のユーザーは、what()やコードなど、定義された最小限のインターフェースに依存することもできます。

たとえば、ユーザーが誤った引数を指定した場合、_std::invalid_argument_をスローするよりも便利でしょうか。他のコードで見られるstd :: exceptionのまだ一般的な使用と組み合わせると、さらに進んでカスタム例外クラス(例:lib_foo_exception)と_std::exception_から派生しないのはなぜですか。

考え?

15
Superlokkus

すべての例外は_std::exception_から継承する必要があります。

たとえば、ComplexOperationThatCouldFailABunchOfWays()を呼び出す必要があり、スローする可能性のあるすべての例外を処理したいとします。すべてが_std::exception_から継承されている場合、これは簡単です。必要なのは単一のcatchブロックだけであり、詳細を取得するための標準インターフェイス(what())があります。

_try {
    ComplexOperationThatCouldFailABunchOfWays();
} catch (std::exception& e) {
    cerr << e.what() << endl;
}
_

例外が_std::exception_を継承しない場合、これは非常に醜くなります。

_try {
    ComplexOperationThatCouldFailABunchOfWays();
} catch (std::exception& e) {
    cerr << e.what() << endl;
} catch (Exception& e) {
    cerr << e.Message << endl;
} catch (framework_exception& e) {
    cerr << e.Details() << endl;
}
_

_runtime_error_または_invalid_argument_をスローするかどうかと、独自の_std::exception_サブクラスを作成してスローするかどうか:私の経験則では、特定のタイプのエラーを異なる方法で処理する必要がある場合は常に新しいサブクラスを導入することですその他のエラー(つまり、別のcatchブロックが必要な場合)。

  • 考えられるすべてのタイプのエラーに対して新しい例外サブクラスを導入すると、それらを個別に処理する必要がない場合でも、クラスが大幅に増加します。
  • 特定の何かを意味するために既存のサブクラスを再利用する場合(つまり、_runtime_error_がスローされた場合hereが一般的なランタイムエラーとは異なるものを意味する場合)、既存のサブクラスの他の使用法と競合するリスクがあります。
  • 私がしないエラーを具体的に処理する必要がある場合、およびスローしているエラーが既存の標準ライブラリのエラーの1つ( _invalid_argument_)として、既存のクラスを再利用します。この場合、新しいクラスを追加してもあまりメリットがありません。 (C++コアガイドラインはここでは私に同意しません。常に独自のクラスを使用することをお勧めします。)

C++コアガイドライン には、さらに議論と例があります。

29
Josh Kelley

ライブラリユーザーとして、ライブラリ関数は標準のライブラリ関数がライブラリの実装で失敗し、それについて何もできない場合にのみstd :: exceptionsをスローすると想定します

これは誤った仮定です。

標準の例外タイプは、「一般的な」使用のために提供されています。これらはonlyが標準ライブラリで使用されるようには設計されていません。

はい、すべてが最終的にstd::exceptionから継承するようにします。多くの場合、これにはstd::runtime_errorまたはstd::logic_errorからの継承が含まれます。実装している例外のクラスに適切なものは何でも。

これはもちろん主観的です。いくつかの一般的なライブラリは、おそらく標準ライブラリからライブラリを切り離すために、標準の例外タイプを完全に無視します。個人的にはこれは非常に利己的だと思います!例外をキャッチすることは、正しく行うのがはるかに難しくなります。

個人的に言えば、私はしばしばstd::runtime_errorを投げてそれで終わります。しかし、それはあなたが求めているものではない、例外クラスをどのように細かくするかについての議論に入っています。