throw 式
エラーの状況を通知し、エラーハンドラを実行します。
目次 |
[編集] 構文
throw expression
|
(1) | ||||||||
throw
|
(2) | ||||||||
[編集] 説明
- try および catch (例外ハンドラ) ブロックについての詳しい情報は try-catch ブロックを参照してください。
- 右辺値式の場合、これはムーブコンストラクタを呼ぶことがあります。
|
(C++17以上) |
- コピー/ムーブはコピー省略の対象です。
|
(C++14以上) |
- その後、この実行のスレッドが最も最近入って出ていない複文またはメンバ初期化子リストを持つマッチする型の例外ハンドラに制御を移します。
例外処理中に発生したエラーの処理については std::terminate および std::unexpected を参照してください。
[編集] 例外オブジェクト
例外オブジェクトは throw
式によって構築される未規定な記憶域内の一時オブジェクトです。
例外オブジェクトの型は最上段の cv 修飾が削除された expression の静的な型です。 配列型および関数型はそれぞれポインタ型および関数へのポインタ型に調節されます。 例外オブジェクトの型が不完全型、抽象クラス型、または void (および cv 修飾された void) 以外の不完全型へのポインタの場合、その throw 式はコンパイル時エラーです。 expression の型がクラス型の場合、そのコピー/ムーブコンストラクタおよびデストラクタは、たとえコピー省略が行われる場合でも、アクセス可能でなければなりません。
他の一時オブジェクトと異なり、例外オブジェクトは catch 節の引数を初期化するときは左辺値引数であるとみなされるため、左辺値参照でキャッチし、変更し、投げ直すことができます。
例外オブジェクトは、投げ直し以外の方法で最後の catch 節が終了するまで (この場合は catch 節の引数の破棄の直後に破棄されます)、またはそのオブジェクトを参照する最後の std::exception_ptr が破棄されるまで (この場合は std::exception_ptr のデストラクタが戻る直前に破棄されます)、存続します。
[編集] スタックの巻き戻し
例外オブジェクトが構築されると、制御の流れは try ブロックの先頭に達するまで逆方向に (コールスタックを上方向に) 移動します。 そしてその地点の紐付けられたすべての catch
ブロックの引数が、出現順に、マッチを見付けるために例外オブジェクトの型と比較されます (この処理の詳細については try-catch を参照してください)。 マッチが見付からなければ、制御の流れは次の try
ブロックまでスタックの巻き戻しを続けます。 マッチが見付かれば、制御の流れはマッチする catch
ブロックにジャンプします。
制御の流れがコールスタックの上方向に移動する際、対応する try ブロックに入って以降、構築されたけれどもまだ破棄されていない自動記憶域期間を持つすべてのオブジェクトに対して、そのコンストラクタの完了の逆順で、デストラクタが呼ばれます。 ローカル変数のデストラクタまたは return 文で使用された一時オブジェクトのデストラクタから例外が投げられた場合は、その関数から返されたオブジェクトに対するデストラクタも呼ばれます。 (C++14以上)
オブジェクト (記憶域期間にかかわらず) のコンストラクタまたは (稀ですが) デストラクタから例外が投げられた場合は、完全に構築された非静的非変種 (C++14未満)メンバおよび基底クラスに対して、コンストラクタの完了の逆順で、デストラクタが呼ばれます。 union ライクなクラスの変種メンバは、コンストラクタからの巻き戻しの場合にのみ破棄され、初期化と破棄の間でアクティブメンバが変更された場合、動作は未定義です。 (C++14以上)
非委譲コンストラクタが成功裏に完了した後、委譲コンストラクタが例外で終了した場合、そのオブジェクトに対するデストラクタは呼ばれます。 | (C++11以上) |
new 式によって呼ばれたコンストラクタから例外が投げられた場合は、マッチする解放関数が (利用可能であれば) 呼ばれます。
この処理はスタックの巻き戻しと言います。
例外オブジェクトの初期化の後かつ例外ハンドラの開始の前に、スタック巻き戻し機構によって直接呼ばれる何らかの関数が例外で終了した場合は、 std::terminate が呼ばれます。 そのような関数には、スコープを終了する自動記憶域期間のオブジェクトのデストラクタや、値渡しでキャッチする引数を初期化するために呼ばれる例外オブジェクトのコピーコンストラクタ (省略されなかった場合) などがあります。
例外が投げられてキャッチされない (std::thread の初期関数、 main 関数、あらゆる静的またはスレッドローカルなオブジェクトのコンストラクタやデストラクタを脱出する例外を含みます) 場合は、 std::terminate が呼ばれます。 キャッチされない例外に対して何らかのスタック巻き戻しが行われるかどうかは処理系定義です。
[編集] ノート
例外を投げ直すときは、例外オブジェクトが継承を用いる (一般的な) 場合のオブジェクトのスライシングを避けるために、2つめの形式を使用しなければなりません。
try { std::string("abc").substr(10); // std::length_error を投げます。 } catch(const std::exception& e) { std::cout << e.what() << '\n'; // throw e; // std::exception 型の新しい例外オブジェクトをコピー初期化します。 throw; // std::length_error 型の例外オブジェクトを投げ直します。 }
throw 式は void 型の prvalue 式として分類されます。 他のあらゆる式と同様に、別の式の部分式であっても構いません。 最も一般的な例は条件演算子です。
double f(double d) { return d > 1e7 ? throw std::overflow_error("too big") : d; } int main() { try { std::cout << f(1e10) << '\n'; } catch (const std::overflow_error& e) { std::cout << e.what() << '\n'; } }
[編集] キーワード
[編集] 例
#include <iostream> #include <stdexcept> struct A { int n; A(int n = 0): n(n) { std::cout << "A(" << n << ") constructed successfully\n"; } ~A() { std::cout << "A(" << n << ") destroyed\n"; } }; int foo() { throw std::runtime_error("error"); } struct B { A a1, a2, a3; B() try : a1(1), a2(foo()), a3(3) { std::cout << "B constructed successfully\n"; } catch(...) { std::cout << "B::B() exiting with exception\n"; } ~B() { std::cout << "B destroyed\n"; } }; struct C : A, B { C() try { std::cout << "C::C() completed successfully\n"; } catch(...) { std::cout << "C::C() exiting with exception\n"; } ~C() { std::cout << "C destroyed\n"; } }; int main () try { // A 基底部分オブジェクトを作成します。 // B の a1 メンバを作成します。 // B の a2 メンバの作成に失敗します。 // B の a1 メンバを巻き戻し破棄します。 // A 基底部分オブジェクトを巻き戻し破棄します。 C c; } catch (const std::exception& e) { std::cout << "main() failed to create C with: " << e.what(); }
出力:
A(0) constructed successfully A(1) constructed successfully A(1) destroyed B::B() exiting with exception A(0) destroyed C::C() exiting with exception main() failed to create C with: error
[編集] 欠陥報告
以下の動作変更欠陥報告は以前に発行された C++ 標準に遡って適用されました。
DR | 適用先 | 発行時の動作 | 正しい動作 |
---|---|---|---|
CWG 1866 | C++14 | variant members were leaked on stack unwinding from constructor | variant members destroyed |
CWG 1863 | C++14 | copy constructor was not required for move-only exception objects when thrown, but copying allowed later | copy constructor required |
CWG 2176 | C++14 | throw from a local variable dtor could skip return value destructor | function return value added to unwinding |