名前空間
変種
操作

例外

提供: cppreference.com
< cpp‎ | language
 
 
C++言語
一般的なトピック
フロー制御
条件付き実行文
繰り返し文 (ループ)
ジャンプ文
関数
関数宣言
ラムダ関数宣言
inline 指定子
例外指定 (非推奨)
noexcept 指定子 (C++11)
例外
名前空間
指定子
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 式dynamic_casttypeidnew 式確保関数、および特定のエラー状況を知らせるために例外を投げると規定されているあらゆる標準ライブラリ関数 (例えば std::vector::atstd::string::substr など) によって、投げられる可能性があります。

例外をキャッチするためには、 throw 式が try ブロックの内側、または try ブロックから呼ばれる関数の内側になければならず、その例外オブジェクトの型にマッチする catch 節がなければなりません。

関数を宣言するとき、その関数が投げても良い例外の型を制限するために、例外指定および noexcept 指定子を提供することができます。

例外処理中に発生したエラーは std::terminate および std::unexpected (C++17以前) によって処理されます。

目次

[編集] 使用方法

throw 式は、 (std::longjmp と同様に) 好きな理由で実行スタックを遡って任意のコードブロックに制御を移すために使用することができますが、その意図された用途はエラー処理です。

[編集] エラー処理

例外は関数からエラーを知らせるために使用されます。 ここでいう「エラー」は、一般的には、以下の内容だけに限定されます[1][2][3]

  1. 事後条件を満たせない。 有効な戻り値のオブジェクトを生成できないなど。
  2. 呼ばなければならない別の関数の事前条件を満たせない。
  3. (非プライベートメンバ関数の場合) クラスの不変条件を (再) 確立できない。

特に、これは、コンストラクタ (RAII も参照) およびほとんどの演算子の失敗は例外を投げることによって報告されなければならないことを暗に示します。

さらに、いわゆる広い契約の関数は、受理できない入力を示すために例外を使用します。 例えば、 std::string::at は事前条件を持ちませんが、範囲外のインデックスを示すために例外を投げます。

[編集] 例外安全性

エラー状況が関数によって報告された後、プログラムの状態に関して追加の保証が提供されることがあります。 一般的に、お互いの厳密なスーパーセットである、以下の4つのレベルの例外保証が知られています[4][5][6]

  1. 無例外 (無失敗) 保証 —— 関数は決して例外を投げません。 デストラクタやスタックの巻き戻し中に呼ばれる可能性のある関数は無例外であることが期待されます (エラーは他の方法で報告されるか隠蔽されます)。 デストラクタはデフォルトで noexcept です。 (C++11およびそれ以降) swap、ムーブコンストラクタ、および強い例外保証を提供するそれらによって使用される他の関数は無失敗である (必ず成功する) ことが期待されます。
  2. 強い例外保証 —— 関数が例外を投げた場合、プログラムの状態はその関数呼び出しの直前の状態にロールバックされます (例えば std::vector::push_back)。
  3. 基本的な例外保証 —— 関数が例外を投げた場合、プログラムは有効な状態です。 クリーンアップが要求されるかもしれませんが、すべての不変条件は保たれます。
  4. 例外保証なし —— 関数が例外を投げた場合、プログラムは有効な状態でない可能性があります。 リソースリーク、メモリ破壊、または他の不変条件を破壊するエラーが発生しているかもしれません。

汎用的なコンポーネントは、さらに例外中立保証を提供することがあります。 テンプレート引数 (例えば std::sortCompare 関数オブジェクトや std::make_sharedT のコンストラクタなど) から例外が投げられた場合、それは変更されずに呼び出し元に伝播されます。

[編集] 例外オブジェクト

あらゆる完全型のオブジェクト、および void への cv ポインタを例外オブジェクトとして投げることができますが、すべての標準ライブラリ関数は、 std::exception から (直接的にまたは間接的に) 派生した型の匿名の一時オブジェクトを、値で投げます。 ユーザ定義の例外は、通常、このパータンに従います。[7][8][9]

不必要な例外オブジェクトのコピーやオブジェクトのスライシングを避けるために、参照でキャッチするのが catch 節のベストプラクティスです。[10][11][12][13]

[編集] 参考文献

  1. H. Sutter (2004) "When and How to Use Exceptions" in Dr. Dobb's
  2. H.Sutter, A. Alexandrescu (2004), "C++ Coding Standards", Item 70
  3. C++ Core Guidelines I.10
  4. B. Stroustrup (2000), "The C++ Programming Language"Appendix E"
  5. H. Sutter (2000) "Exceptional C++"
  6. D. Abrahams (2001) "Exception Safety in Generic Components"
  7. D. Abrahams (2001) "Error and Exception Handling"
  8. isocpp.org Super-FAQ "What should I throw?"
  9. C++ Core Guidelines E.14
  10. C++ Core Guidelines E.15
  11. S. Meyers (1996) "More Effective C++" Item 13
  12. isocpp.org Super-FAQ "What should I catch?"
  13. H.Sutter, A. Alexandrescu (2004) "C++ Coding Standards" Item 73