名前空間
変種
操作

throw 式

提供: cppreference.com
< cpp‎ | language
 
 
C++言語
一般的なトピック
フロー制御
条件付き実行文
繰り返し文 (ループ)
ジャンプ文
関数
関数宣言
ラムダ関数宣言
inline 指定子
例外指定 (C++20未満)
noexcept 指定子 (C++11)
例外
throw
名前空間
指定子
decltype (C++11)
auto (C++11)
alignas (C++11)
記憶域期間指定子
初期化
代替表現
リテラル
ブーリアン - 整数 - 浮動小数点
文字 - 文字列 - nullptr (C++11)
ユーザ定義 (C++11)
ユーティリティ
属性 (C++11)
typedef 宣言
型エイリアス宣言 (C++11)
キャスト
暗黙の変換 - 明示的な変換
static_cast - dynamic_cast
const_cast - reinterpret_cast
メモリ確保
クラス
クラス固有の関数特性
特別なメンバ関数
テンプレート
その他
 
 

エラーの状況を通知し、エラーハンドラを実行します。

目次

[編集] 構文

throw expression (1)
throw (2)

[編集] 説明

try および catch (例外ハンドラ) ブロックについての詳しい情報は try-catch ブロックを参照してください。
1) まず、 expression から例外オブジェクトコピー初期化し (これは左辺値式の場合はムーブコンストラクタを呼ぶ可能性があり、そのコピー/ムーブはコピー省略の対象です)、その後、この実行のスレッドが最も最近入って出ていない複文またはメンバ初期化子リストを持つマッチする型の例外ハンドラに制御を移します。 たとえコピー初期化がムーブコンストラクタを選択する場合でも、左辺値からのコピー初期化は well-formed でなければならず、デストラクタはアクセス可能でなければなりません。 (C++14以上)
2) 現在処理されている例外を投げ直します。 現在の catch ブロックの実行を放棄し、次のマッチする例外ハンドラ (しかし同じ try ブロックの後の別の catch 節ではない (その複文は「終了済み」とみなされます)) に制御を移します。 既存の例外オブジェクトが再利用され、新しいオブジェクトは作られません。 この形式は例外が現在処理されているときにのみ許されます (そうでなければ std::terminate を呼びます)。 関数 try ブロックに紐付けられた catch 節は、コンストラクタで使用された場合は、投げ直すことによって終了しなければなりません。

例外処理中に発生したエラーの処理については 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';
    }
}

[編集] キーワード

throw

[編集]

#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

[編集] 関連項目