try ブロック
1つ以上の例外ハンドラ (catch 節) を複文と紐付けます。
目次 |
[編集] 構文
try compound-statement handler-sequence
|
|||||||||
ただし handler-sequence は1つ以上の handler の並びであり、 handler は以下の構文を持ちます。
catch ( attr(オプション) type-specifier-seq declarator ) compound-statement
|
(1) | ||||||||
catch ( attr(オプション) type-specifier-seq abstract-declarator(オプション) ) compound-statement
|
(2) | ||||||||
catch ( ... ) compound-statement
|
(3) | ||||||||
compound-statement | - | 波括弧で囲まれた文の並び。 |
attr(C++11) | - | オプショナルな属性のリスト。 仮引数に適用されます。 |
type-specifier-seq | - | 仮引数宣言の一部。 関数の仮引数リストの場合と同じです。 |
declarator | - | 仮引数宣言の一部。 関数の仮引数リストの場合と同じです。 |
abstract-declarator | - | 名前なし仮引数宣言の一部。 関数の仮引数リストの場合と同じです。 |
try { /* */ } catch (const std::exception& e) { /* */ }
try { /* */ } catch (const std::exception&) { /* */ }
try { /* */ } catch (...) { /* */ }
[編集] 説明
- throw 式についてのさらなる情報は throw 式を参照してください。
try ブロックは文であり、文が現れることができる任意の場所に (つまり、複文 (関数本体である複文も含みます) 内の文のひとつとして) 現れることができます。 関数本体の周りの try ブロックについては関数 try ブロックを参照してください。 以下の説明は try ブロックと関数 try ブロックの両方に適用されます。
catch 節の仮引数 (type-specifier-seq と declarator または type-specifier-seq と abstract-declarator) は、どの型の例外がその catch 節への突入を発生させるかを決定します。 右辺値参照型、抽象クラス、不完全型、不完全型へのポインタにはできません (ただし void (cv 修飾されていても構いません) へのポインタは使用できます)。 仮引数の型が配列型または関数型の場合は、対応するポインタ型として扱われます (関数宣言と同様です)。
compound-statement 内の何らかの文によって E
型の例外が投げられると、 handler-seq 内のそれぞれの catch 節の仮引数の型 T
に対して、 catch 節が並べられている順番で、マッチが試みられます。 例外は、以下のいずれかが真の場合、マッチします。
-
E
とT
が同じ型である (T
の最上段の cv 修飾子は無視します)。 -
T
がE
(またはその cv 修飾された型) への左辺値参照である。 -
T
がE
の曖昧でないパブリックな基底クラスである。 -
T
がE
の曖昧でないパブリックな基底クラスへの参照である。 -
T
がU
(またはその cv 修飾された型) またはconst U&
(C++14以上) であり、U
がポインタまたはメンバポインタ (C++17以上)型であり、E
が以下のうちの1つ以上によってU
に暗黙に変換できるポインタまたはメンバポインタ (C++17以上)である。
(C++17以上) |
-
T
がポインタまたはメンバポインタまたは const ポインタへの参照 (C++14以上)であり、E
が std::nullptr_t である。
try { f(); } catch (const std::overflow_error& e) { // f() が std::overflow_error を投げた場合は、ここが実行されます (同じ型のルール)。 } catch (const std::runtime_error& e) { // f() が std::underflow_error を投げた場合は、ここが実行されます (基底クラスのルール)。 } catch (const std::exception& e) { // f() が std::logic_error を投げた場合は、ここが実行されます (基底クラスのルール)。 } catch (...) { // f() が std::string や int やその他のあらゆる無関係な型を投げた場合は、ここが実行されます。 }
全キャッチ節 catch (...) はあらゆる型の例外にマッチします。 これは、存在する場合は、 handler-seq 内の最後の catch 節でなければなりません。 全キャッチブロックは例外を投げない保証を提供する関数から未捕捉の例外が漏れる可能性がないことを保証するために使用できます。
すべての catch 節を調べた後、マッチが見付からなかった場合は、 throw 式で説明されている通りに、含んでいる try ブロックに例外の伝播が続行されます。 含んでいる try ブロックが残っていない場合は、 std::terminate が実行されます (この場合、スタックの巻き戻しが発生するかどうかは処理系定義です。 捕捉されない例外が投げられると、いかなるデストラクタも呼ばずにプログラムを終了することが許されます)。
catch 節に突入するとき、その仮引数が例外の型の基底クラスである場合、仮引数は例外オブジェクトの基底クラス部分オブジェクトからコピー初期化されます。 そうでなければ、仮引数は例外オブジェクトからコピー初期化されます (このコピーはコピー省略の対象です)。
try { std::string("abc").substr(10); // std::length_error を投げます。 // } catch (std::exception e) { // 基底 std::exception からコピー初期化されます。 // std::cout << e.what(); // length_error の情報は失われます。 // } } catch (const std::exception& e) { // 多相オブジェクトの基底への参照。 std::cout << e.what(); // length_error 情報が表示されます。 }
catch 節の引数が参照型の場合、それに対して行われたあらゆる変更は例外オブジェクトに反映され、その例外が throw; で投げ直された場合、別の例外ハンドラから観察できます。 引数が参照でない場合、それに対して行われたあらゆる変更はローカルであり、その生存期間はハンドラが終了したときに終了します。
catch 節内では、例外を std::exception_ptr 内にキャプチャするために std::current_exception を使用でき、ネストした例外を構築するために std::throw_with_nested を使用できます。 | (C++11以上) |
例外を投げるまたは投げ直すことによる以外に、 return、 continue、 break、 goto を用いて、または compound-statement の終わりに達することによって、普通の try ブロック(関数 try ブロックは含みません) の後の catch 節を終了できます。 いずれの場合でも、例外オブジェクトは破棄されます (ただし、それを参照する std::exception_ptr のインスタンスが存在する場合は除きます)。
[編集] ノート
throw 式 throw NULL; は、例外オブジェクトの型が int かもしれないため、ポインタの catch 節にマッチする保証はありませんが、 throw nullptr; は、あらゆるポインタまたはメンバポインタの catch 節に確実にマッチします。
派生クラスに対する catch 節が基底クラスに対する catch 節より後に配置されている場合、派生の catch 節は実行されることはありません。
try { f(); } catch (const std::exception& e) { // f() が std::runtime_error を投げた場合に実行されます。 } catch (const std::runtime_error& e) { // デッドコード。 }
try ブロックを終了するために goto が使用され、その goto
によって実行されたブロックスコープの自動変数のデストラクタのいずれかが例外を投げた場合、その例外はその変数が定義された try ブロックによってキャッチされます。
label: try { T1 t1; try { T2 t2; if(condition) goto label; //t2 破棄し、その後 t1 を破棄し、その後 label にジャンプします。 } catch (...) { } // t2 のデストラクタからの例外をキャッチします。 } catch (...) { } // t1 のデストラクタからの例外をキャッチします。
[編集] キーワード
[編集] 例
以下の例は try-catch
ブロックのいくつかの使用方法をデモンストレーションします。
#include <iostream> #include <vector> int main() { try { std::cout << "Throwing an integer exception...\n"; throw 42; } catch (int i) { std::cout << " the integer exception was caught, with value: " << i << '\n'; } try { std::cout << "Creating a vector of size 5... \n"; std::vector<int> v(5); std::cout << "Accessing the 11th element of the vector...\n"; std::cout << v.at(10); // vector::at() によって std::out_of_range が投げられます。 } catch (const std::exception& e) { // 基底への参照によってキャッチされます。 std::cout << " a standard exception was caught, with message '" << e.what() << "'\n"; } }
出力例:
Throwing an integer exception... the integer exception was caught, with value: 42 Creating a vector of size 5... Accessing the 11th element of the vector... a standard exception was caught, with message 'out_of_range'