C++例外処理完全ガイド:try、catch、throwの使い方
例外とは、プログラム実行中に発生する問題です。C++の例外は、プログラム実行中に発生する例外的な状況(ゼロ除算の試みなど)への対応です。
例外は、プログラムのある部分から別の部分へ制御を移す方法を提供します。C++の例外処理は、try、catch、throw の3つのキーワードに基づいて構築されています。
throw : 問題が発生したときにプログラムが例外をスローします。これは throw キーワードを使用して行います。
catch : プログラムの問題を処理したい場所で、例外ハンドラを使用して例外をキャッチします。catch キーワードは例外の捕捉を示します。
try : 特定の例外が有効になるコードブロックを識別します。1つ以上の catch ブロックが続きます。
ブロックが例外を発生させると仮定すると、try と catch キーワードの組み合わせでメソッドが例外を捕捉します。try/catch ブロックは、例外を生成する可能性のあるコードの周りに配置されます。try/catch ブロック内のコードは保護されたコードと呼ばれ、try/catch の構文は以下の通りです:
try {
// 保護されたコード
} catch( ExceptionName e1 ) {
// catch ブロック
} catch( ExceptionName e2 ) {
// catch ブロック
} catch( ExceptionName eN ) {
// catch ブロック
}
try ブロックが異なる状況で複数の例外を発生させる場合、複数の catch 文を列記して異なるタイプの例外を捕捉できます。
例外のスロー
コードブロック内のどこでも throw 文を使用して例外をスローできます。throw 文のオペランドが例外の型を決定し、任意の式を指定でき、式の結果の型がスローされる例外の型になります。
ゼロ除算条件が発生したときに例外をスローする例:
double division(int a, int b) {
if( b == 0 ) {
throw "Division by zero condition!";
}
return (a/b);
}
例外のキャッチ
try ブロックに続く catch ブロックは、あらゆる例外を捕捉します。キャッチしたい例外の型を指定でき、これは catch キーワードに続く括弧内の例外宣言によって決まります。
try {
// 保護されたコード
} catch( ExceptionName e ) {
// ExceptionName 例外を処理するコード
}
上記コードは ExceptionName 型の例外を捕捉します。try ブロックでスローされるあらゆるタイプの例外を catch ブロックで処理したい場合、例外宣言を囲む括弧内に省略記号 ... を置きます:
try {
// 保護されたコード
} catch(...) {
// あらゆる例外を処理するコード
}
以下は、ゼロ除算例外をスローし、catch ブロックで捕捉する例です:
Live Demo#include <iostream>
using namespace std;
double division(int a, int b) {
if( b == 0 ) {
throw "Division by zero condition!";
}
return (a/b);
}
int main () {
int x = 50;
int y = 0;
double z = 0;
try {
z = division(x, y);
cout << z << endl;
} catch (const char* msg) {
cerr << msg << endl;
}
return 0;
}
const char* 型の例外を発生させているため、この例外を捕捉する際は catch ブロックで const char* を使用する必要があります。上記コードをコンパイルして実行すると、以下の結果が得られます:
Division by zero condition!
C++標準例外
C++は <exception> で定義される標準例外のリストを提供しており、これらをプログラムで使用できます。これらは以下の親子クラス階層に配置されています:
上記階層にある各例外の簡単な説明:
| No. | 例外と説明 |
|---|---|
| 1 | std::exception すべての標準C++例外の親クラスである例外。 |
| 2 | std::bad_alloc new によってスローされる可能性がある。 |
| 3 | std::bad_cast dynamic_cast によってスローされる可能性がある。 |
| 4 | std::bad_exception C++プログラムでの予期しない例外を処理するのに便利なデバイス。 |
| 5 | std::bad_typeid typeid によってスローされる可能性がある。 |
| 6 | std::logic_error コードを読むことで理論的に検出可能な例外。 |
| 7 | std::domain_error 数学的に無効なドメインが使用されたときにスローされる例外。 |
| 8 | std::invalid_argument 無効な引数によってスローされる。 |
| 9 | std::length_error 大きすぎる std::string が作成されたときにスローされる。 |
| 10 | std::out_of_range 例えば std::vector や std::bitset<>::operator[]() の 'at' メソッドによってスローされる可能性がある。 |
| 11 | std::runtime_error コードを読むことで理論的に検出できない例外。 |
| 12 | std::overflow_error 数学的オーバーフローが発生したときにスローされる。 |
| 13 | std::range_error 範囲外の値を格納しようとしたときに発生。 |
| 14 | std::underflow_error 数学的アンダーフローが発生したときにスローされる。 |
独自例外の定義
exception クラスを継承しオーバーライドすることで、独自の例外を定義できます。以下は、std::exception クラスを使用して標準的な方法で独自の例外を実装する例です:
Live Demo#include <iostream>
#include <exception>
using namespace std;
struct MyException : public exception {
const char * what () const throw () {
return "C++ Exception";
}
};
int main() {
try {
throw MyException();
} catch(MyException& e) {
std::cout << "MyException caught" << std::endl;
std::cout << e.what() << std::endl;
} catch(std::exception& e) {
// その他のエラー
}
}
これにより以下の結果が得られます:
MyException caught C++ Exception
ここでは、what() は例外クラスが提供するパブリックメソッドで、すべての子例外クラスによってオーバーライドされています。これは例外の原因を返します。
C言語
- C++演算子完全ガイド:算術・代入・関係・論理・ビット演算子と実例
- C++コメント完全ガイド:読みやすく保守しやすいコードのためのベストプラクティス
- C++クラステンプレート完全ガイド:実践的なジェネリックプログラミング
- C言語 ファイル入出力: fopen, fprintf, fread, fseek をマスターする
- C++例外処理をマスター:try、catch、throwの実践例
- C言語エラーハンドリングのマスター:ベストプラクティスとテクニック
- C++プログラミング言語:概要と主要機能
- C++定数とリテラル完全解説:型、構文、ベストプラクティス
- C++演算子完全ガイド:種類、使い方、ベストプラクティス
- Python例外処理をマスター:try、except、finally、raiseの効果的な活用
- Java例外ハンドリング完全攻略:try-catch、finally、throw、throws