try、throw、および catch ステートメント (C++)
C++ で例外処理を実装するには、try、throw、catch の式を使用します。
まず、try ブロックを使用して、例外をスローする可能性がある 1 つ以上のステートメントを囲みます。
throw は、try ブロックで例外条件 (多くの場合はエラー) が発生したことを通知するために使用します。 任意の型のオブジェクトを throw 式のオペランドとして使用できます。 通常、このオブジェクトを使用してエラーに関する情報を通知します。 ほとんどの場合、std::exception クラスを使用するか、標準ライブラリで定義されているその派生クラスのいずれかを使用することをお勧めします。 これらのいずれのクラスも適さない場合は、std::exception から派生させた独自の例外クラスを使用することをお勧めします。
スローされる可能性のある例外を処理するために、1 つ以上の catch ブロックを try ブロックの直後に実装します。 各 catch ブロックには、処理できる例外の型を指定します。
次の例では、try ブロックとそのハンドラーを示しています。 GetNetworkResource() では、ネットワーク接続を介してデータを取得するとします。また、2 つの型の例外として std::exception から派生させたユーザー定義のクラスを使用するとします。 例外は catch ステートメントの const 参照でキャッチしています。 例外は値でスローし、const 参照でキャッチすることをお勧めします。
使用例
MyData md;
try {
// Code that could throw an exception
md = GetNetworkResource();
}
catch (const networkIOException& e) {
// Code that executes when an exception of type
// networkIOException is thrown in the try block
// ...
// Log error message in the exception object
cerr << e.what();
}
catch (const myDataFormatException& e) {
// Code that handles another exception type
// ...
cerr << e.what();
}
// The following syntax shows a throw expression
MyData GetNetworkResource()
{
// ...
if (IOSuccess == false)
throw networkIOException("Unable to connect");
// ...
if (readError)
throw myDataFormatException("Format error");
// ...
}
解説
try 句の後ろのコードは、コードの保護されたコード セクションです。 throw 式が例外をスローします (発生させます)。 catch 句の後ろのコード ブロックが例外ハンドラーです。 このハンドラーは、throw 式と catch 式とで例外の型が一致する場合に、スローされた例外をキャッチします。 catch ブロックの型の一致を決定する規則の一覧については、「Catch ブロックの評価方法 (C++)」を参照してください。 catch ステートメントで型ではなく省略記号 (...) を指定した場合、catch ブロックはいずれの型の例外も処理します。 /EHa オプションを指定してコンパイルすると、C 構造化例外とシステムまたはアプリケーションで生成された例外 (メモリ保護違反、ゼロ除算違反、浮動小数点演算違反など) を処理できるようになります。 catch ブロックは一致する型を検索するプログラムの順序で処理されるため、省略記号を指定したハンドラーは関連付ける try ブロックの最後のハンドラーにする必要があります。 catch(...) は慎重に使用してください。プログラムの実行が継続されるには、キャッチした特定の例外を処理する方法を catch ブロックに記述する必要があります。 catch(...) ブロックは通常、プログラムの実行を停止する前に、エラーを記録して特別なクリーンアップを実行するために使用します。
オペランドのない throw 式は現在処理中の例外を再スローします。 この方法は例外を再スローするときにお勧めします。元の例外のポリモーフィックな型情報が保持されるためです。 このような式は catch ハンドラー内か、catch ハンドラーから呼び出された関数内でのみ使用する必要があります。 再スローされた例外オブジェクトはコピーではなく元の例外オブジェクトです。
try {
throw CSomeOtherException();
}
catch(...) {
// Catch all exceptions – dangerous!!!
// Respond (perhaps only partially) to the exception, then
// re-throw to pass the exception to some other handler
// ...
throw;
}