名前空間
変種
操作

例外を処理する

From cppreference.com
< cpp‎ | language
 
 
C++言語
全般
フロー制御
条件実行文
if
繰り返し文 (ループ)
for
範囲for (C++11)
ジャンプ文
関数
関数宣言
ラムダ式
inline指定子
動的例外仕様 (C++17まで*)
noexcept指定子 (C++11)
例外

catchハンドラ
名前空間
指定子
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
記憶域期間指定子
初期化
代替表現
リテラル
ブーリアン - 整数 - 浮動小数点数
文字 - 文字列 - nullptr (C++11)
ユーザー定義 (C++11)
ユーティリティ
属性 (C++11)
typedef宣言
型エイリアス宣言 (C++11)
キャスト
メモリ確保
クラス
クラス固有の関数プロパティ
explicit (C++11)
static

特殊メンバ関数
テンプレート
その他
 
 
例外
tryブロック
例外を送出する
例外を処理する
例外仕様
    noexcept 指定 (C++11)
    動的例外指定 (C++17* まで)
noexcept 演算子 (C++11)
 

例外はハンドラによって処理されます。

目次

[編集] ハンドラ

catch ( attr (省略可能) type-specifier-seq declarator ) compound-statement (1)
catch ( attr (省略可能) type-specifier-seq abstract-declarator (省略可能) ) compound-statement (2)
catch ( ... ) compound-statement (3)
1) 名前付きパラメータを持つハンドラ。
2) 名前なしパラメータを持つハンドラ。
3) あらゆる種類の例外に一致するハンドラ。
attr - (C++11以降) 任意の数の属性。パラメータに適用される。
type-specifier-seq - 仮パラメータ宣言の一部で、関数のパラメータリストと同様。
declarator (宣言子) - パラメータ宣言の一部で、関数のパラメータリストと同様。
abstract-declarator - 名前なしパラメータ宣言の一部で、関数のパラメータリストと同様。
compound-statement - 複合ステートメント


ハンドラ内のパラメータ宣言は、そのハンドラが入力される原因となる例外の型を記述します。

パラメータが以下のいずれかの型として宣言されている場合、プログラムは不正です。

(C++11以降)
  • (cv修飾子が付いている可能性がある) void 以外の不完全型へのポインタ
  • 不完全型への左辺値参照

パラメータが「Tの配列」または関数型Tとして宣言されている場合、型は「Tへのポインタ」に調整されます。

パラメータ型がTのハンドラは、「型Tのハンドラ」と略すことができます。

[編集] 例外のマッチング

tryブロックは多数のハンドラと関連付けられ、これらのハンドラはハンドラシーケンスを形成します。tryブロックから例外がスローされると、シーケンス内のハンドラが出現順に試され、例外に一致するかどうか確認されます。

以下のいずれかの条件が満たされた場合、ハンドラは型E例外オブジェクトと一致します。

  • ハンドラが「cv修飾子が付いている可能性があるT」または「cv修飾子が付いている可能性があるTへの左辺値参照」の型であり、かつ以下のいずれかの条件が満たされる場合:
  • ETが同じ型である(トップレベルのcv修飾子は無視される)。
  • TEの曖昧性のない公開基底クラスである。
  • ハンドラが「cv修飾子が付いている可能性があるT」またはconst T&の型であり、ここでTがポインタまたはメンバへのポインタ型であり、かつ以下のいずれかの条件が満たされる場合:
  • Eが、以下のいずれかの変換によってTに変換できるポインタまたはメンバへのポインタ型である場合:
  • privateまたはprotectedまたは曖昧なクラスへのポインタへの変換を含まない標準ポインタ変換
(C++17以降)
(C++11以降)

catch (...)ハンドラは、あらゆる型の例外に一致します。存在する場合、ハンドラシーケンスの最後のハンドラでなければなりません。このハンドラは、nothrow例外保証を提供する関数から、キャッチされない例外が漏れることがないようにするために使用できます。

try
{
    f();
}
catch (const std::overflow_error& e)
{} // this executes if f() throws std::overflow_error (same type rule)
catch (const std::runtime_error& e)
{} // this executes if f() throws std::underflow_error (base class rule)
catch (const std::exception& e)
{} // this executes if f() throws std::logic_error (base class rule)
catch (...)
{} // this executes if f() throws std::string or int or any other unrelated type

tryブロックのハンドラの中で一致するものが見つからない場合、一致するハンドラの検索は、動的に囲むtryブロック(同じスレッドの)(C++11以降)で続行されます。

一致するハンドラが見つからない場合、std::terminateが呼び出されます。std::terminateのこの呼び出しの前にスタックが巻き戻されるかどうかは実装定義です。

[編集] 例外の処理

例外がスローされると、制御は型が一致する最も近いハンドラに転送されます。「最も近い」とは、tryキーワードに続く複合ステートメントまたはメンバ初期化子リスト(存在する場合)が制御スレッドによって最も最近入力され、まだ終了していないハンドラを意味します。

[編集] ハンドラパラメータの初期化

パラメータリスト(存在する場合)で宣言された、型が「cv修飾子が付いている可能性があるT」または「cv修飾子が付いている可能性があるTへの左辺値参照」のパラメータは、型E例外オブジェクトから次のように初期化されます。

  • TEの基底クラスである場合、パラメータは例外オブジェクトの対応する基底クラスサブオブジェクトを指定する型Tの左辺値からコピー初期化されます。
  • それ以外の場合、パラメータは例外オブジェクトを指定する型Eの左辺値からコピー初期化されます。

パラメータの寿命は、ハンドラ内で初期化された自動記憶期間を持つオブジェクトの破棄後に、ハンドラが終了すると終了します。

パラメータがオブジェクトとして宣言されている場合、そのオブジェクトへの変更は例外オブジェクトに影響しません。

パラメータがオブジェクトへの参照として宣言されている場合、参照されるオブジェクトへの変更は例外オブジェクトへの変更であり、そのオブジェクトが再スローされた場合に影響します。

[編集] ハンドラの起動

ハンドラ(存在する場合)のパラメータの初期化が完了すると、ハンドラはアクティブであるとみなされます。

また、スローによってstd::terminateが入力されると、暗黙のハンドラがアクティブであるとみなされます。

ハンドラが終了すると、ハンドラはアクティブであるとはみなされません。

最も最近アクティブになり、かつまだアクティブなハンドラを持つ例外は、現在処理中の例外と呼ばれます。そのような例外は再スローできます。

[編集] 制御フロー

ハンドラのcompound-statement制御フロー限定ステートメントです。

void f()
{
    goto label;     // error
    try
    {
        goto label; // error
    }
    catch (...)
    {
        goto label: // OK
        label: ;
    }
}

[編集] 注釈

スタック巻き戻しは、制御がハンドラに転送されている間に発生します。ハンドラがアクティブになると、スタック巻き戻しはすでに完了しています。

throw 0というthrow式によってスローされた例外は、ポインタ型またはメンバへのポインタ型のハンドラには一致しません。

  • 代わりにthrow nullptrを使用すると、そのようなハンドラに一致するヌルポインタをスローできます。
(C++11以降)

例外オブジェクトは決して配列型や関数型を持つことはできないため、配列型や関数型への参照を持つハンドラは、いかなる例外オブジェクトにも一致しません。

例えば、対応する曖昧性のない公開基底クラスのハンドラの後ろに、最終派生クラスのハンドラを配置するなど、決して実行されないハンドラを作成することも可能です。

try
{
    f();
}
catch (const std::exception& e)
{} // will be executed if f() throws std::runtime_error
catch (const std::runtime_error& e)
{} // dead code!

多くの実装は、CWG issue 388の解決策を、非constポインタ型への参照ハンドラにも過度に拡張しています。

int i;
try
{
    try
    {
        throw static_cast<float*>(nullptr);
    }
    catch (void*& pv)
    {
        pv = &i;
        throw;
    }
}
catch (const float* pf)
{
    assert(pf == nullptr); // should pass, but fails on MSVC and Clang
}

[編集] キーワード

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() throws std::out_of_range
    }
    catch (const std::exception& e) // caught by reference to base
    {
        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'

[編集] 欠陥報告

以下の動作変更を伴う欠陥報告が、以前に公開されたC++標準に遡って適用されました。

DR 適用対象 公開された動作 正しい動作
CWG 98 C++98 switchステートメントは制御をハンドラに転送できる。 禁止された
CWG 210 C++98 throw式がハンドラに対してマッチングされていた。 例外オブジェクトが
ハンドラに対してマッチングされる。
CWG 388 C++98 ポインタまたはメンバへのポインタ型の例外は
異なる型へのconst参照ではマッチングできなかった。
変換可能な場合に
マッチング可能になった。
CWG 1166 C++98 型が抽象クラス型への参照であるハンドラがマッチングされた場合、
動作は未定義であった。
抽象クラス型は
ハンドラには許可されない。
CWG 1769 C++98 ハンドラの型が例外オブジェクトの型の基底である場合、
変換コンストラクタがハンドラパラメータの初期化に
使用される可能性があった。
パラメータは、例外オブジェクトの
対応する基底クラスサブオブジェクトから
コピー初期化される。
CWG 2093 C++98 オブジェクト型へのポインタの例外オブジェクトは、修飾変換によって
オブジェクト型へのポインタのハンドラとマッチングできなかった。
許可

[編集] 参照

  • C++23標準 (ISO/IEC 14882:2024)
  • 14.4 例外の処理 [except.handle]
  • C++20 standard (ISO/IEC 14882:2020)
  • 14.4 例外の処理 [except.handle]
  • C++17 standard (ISO/IEC 14882:2017)
  • 18.3 例外の処理 [except.handle]
  • C++14 standard (ISO/IEC 14882:2014)
  • 15.3 例外の処理 [except.handle]
  • C++11 standard (ISO/IEC 14882:2011)
  • 15.3 例外の処理 [except.handle]
  • C++03 標準 (ISO/IEC 14882:2003)
  • 15.3 例外の処理 [except.handle]
  • C++98 標準 (ISO/IEC 14882:1998)
  • 15.3 例外の処理 [except.handle]

[編集] 関連項目

English 日本語 中文(简体) 中文(繁體)