関数 try ブロック
関数の本体の周囲に例外ハンドラを確立します。
[編集]構文
関数 try ブロックは、関数定義の一部である function-body に対する、代替構文形式のひとつです。
try ctor-initializer(オプション)compound-statementhandler-sequence | |||||||||
ctor-initializer | - | メンバ初期化子リスト。 コンストラクタでのみ使用できます。 |
compound-statement | - | 関数の本体を構成する波括弧で囲まれた文の並び。 |
handler-sequence | - | 1つ以上の catch 節の並び。 |
[編集]説明
関数 try ブロックは一連の catch 節を関数本体全体、およびメンバ初期化子リスト (コンストラクタで使用された場合) に紐付けます。 関数本体内のいずれかの文、またはいずれかのメンバまたは基底のコンストラクタ (コンストラクタの場合)、または何らかのメンバまたは基底のデストラクタ (デストラクタの場合) から投げられたすべての例外は、普通の try ブロックで投げられた例外と同様の方法で、 handler-sequence に制御を移します。
struct S {std::string m; S(conststd::string& arg)try: m(arg, 100){std::cout<<"constructed, mn = "<< m <<'\n';}catch(conststd::exception& e){std::cerr<<"arg="<< arg <<" failed: "<< e.what()<<'\n';// ここで暗黙の throw が行われます。}};
コンストラクタに対する関数 try ブロックのいかなる catch 節に入るよりも前に、完全に構築されたすべてのメンバおよび基底が破棄されます。
関数 try ブロックが委譲コンストラクタに対するものであり、非委譲コンストラクタを呼んで正常に完了したけれども委譲コンストラクタの本体が例外を投げた場合、その関数 try ブロックのいかなる catch 節に入るよりも前に、そのオブジェクトのデストラクタが完了します。 | (C++11以上) |
デストラクタに対する関数 try ブロックのいかなる catch 節に入るよりも前に、すべての基底および非変種メンバが破棄されます。
コンストラクタまたはデストラクタに対して使用される関数 try ブロックの catch 節がそのオブジェクトの基底または非静的メンバにアクセスした場合、動作は未定義です。
コンストラクタに対する関数 try ブロックのすべての catch 節は例外を投げることによって終了しなければなりません。 制御がそのようなハンドラの終わりに達した場合は、 throw; によって行われたかのように現在の例外が自動的に投げ直されます。 コンストラクタに対する関数 try ブロックの catch 節内では return 文は使用できません。
デストラクタに対する関数 try ブロックの catch 節の終わりに達した場合も、 throw; によって行われたかのように現在の例外が自動的に投げ直されますが、 return 文は使用できます。
それ以外のすべての関数については、その関数の戻り値の型が void (cv 修飾されていても構いません) であれば catch 節の終わりへの到達は return; と同等であり、そうでなければ動作は未定義です。
[編集]ノート
関数 try ブロックの主な目的は、コンストラクタ内のメンバ初期化子リストから投げられる例外に対して、ログを記録して投げ直す、例外オブジェクトを変更して投げ直す、代わりに別の例外を投げる、プログラムを終了するなどの対応を行うことです。 デストラクタや普通の関数で使用されることは稀です。
関数 try ブロックは、値渡しされた関数引数のコピー/ムーブコンストラクタおよびデストラクタによって投げられた例外はキャッチしません。 それらの例外は呼び出し元の文脈で投げられます。
スレッドのトップレベル関数の関数 try ブロックはスレッドローカルオブジェクトのコンストラクタおよびデストラクタから投げられた例外をキャッチしません (関数スコープのスレッドローカル変数のコンストラクタは除きます)。 | (C++11以上) |
同様に、 main() 関数の関数 try ブロックは静的オブジェクトのコンストラクタおよびデストラクタから投げられた例外をキャッチしません (関数ローカルな静的変数のコンストラクタは除きます)。
関数引数のスコープおよび生存期間は handler-sequence の終わりまで延長されます (関数本体の中で宣言されたオブジェクトは延長されません)。
int f(int n =2)try{++n;// 関数引数をインクリメントします。throw n;}catch(...){++n;// n はスコープ内であり、関数引数を未だ参照します。assert(n ==4);return n;}