C++プログラムでは、さまざまな種類のエラーが発生する可能性があります。これらのエラーを適切に処理するためには、例外処理の仕組みを理解し、実装することが重要です。例外処理は、プログラムの正常な実行フローを維持し、エラーが発生した場合でも安全に動作を継続するための手段です。この記事では、C++での例外処理の基本的な考え方と具体的な使い方について、サンプルコードと共にわかりやすく解説します。
例外とは何か?
例外とは、プログラムの実行中に予期しない事態が発生し、通常の処理を続行できなくなった際に発生するエラーです。例外処理を行うことで、エラーの原因に応じた適切な対応を行い、プログラムが異常終了しないようにします。C++では、try
, catch
, throw
という3つのキーワードを使用して例外処理を行います。
tryブロック
try
ブロックは、エラーが発生する可能性のあるコードを囲むために使用します。もしtry
ブロック内で例外が発生すると、その後のコードは実行されずに、対応するcatch
ブロックが呼び出されます。
catchブロック
catch
ブロックは、try
ブロックで発生した例外を受け取り、それに対する処理を行います。catch
ブロックは、発生した例外の型に基づいて複数定義することが可能です。
throwキーワード
throw
キーワードは、例外を発生させるために使用します。throw
を使うことで、特定のエラー条件に遭遇したときに例外を投げ、その後の処理をcatch
ブロックに任せることができます。
C++での基本的な例外処理の例
ここでは、C++での基本的な例外処理の使い方を示します。このサンプルコードでは、整数の割り算を行い、ゼロによる除算が発生した場合に例外を投げて処理します。
#includeint divide(int a, int b) { if (b == 0) { throw std::runtime_error("Division by zero!"); } return a / b; } int main() { int x = 10; int y = 0; try { int result = divide(x, y); std::cout << "Result: " << result << std::endl; } catch (const std::exception& e) { std::cerr << "Error: " << e.what() << std::endl; } return 0; }
このプログラムでは、divide
関数内でゼロ除算が発生した場合にthrow
キーワードを使って例外を投げています。try
ブロック内でdivide
関数を呼び出し、例外が発生した場合はcatch
ブロックでその例外を捕まえてエラーメッセージを出力します。実行結果は以下のようになります。
Error: Division by zero!
複数の例外をキャッチする
C++では、異なる種類の例外を投げることができ、それぞれの例外に対して異なるcatch
ブロックを用意することが可能です。例えば、整数のゼロ除算に加えて、負数の除算に対しても別の例外を投げるケースを考えてみましょう。
#includeint divide(int a, int b) { if (b == 0) { throw std::runtime_error("Division by zero!"); } if (b < 0) { throw std::invalid_argument("Negative divisor!"); } return a / b; } int main() { int x = 10; int y = -2; try { int result = divide(x, y); std::cout << "Result: " << result << std::endl; } catch (const std::invalid_argument& e) { std::cerr << "Invalid argument: " << e.what() << std::endl; } catch (const std::exception& e) { std::cerr << "Error: " << e.what() << std::endl; } return 0; }
このコードでは、負数の除算が発生した場合にはstd::invalid_argument
例外を投げ、それに対応するcatch
ブロックで処理しています。実行結果は以下の通りです。
Invalid argument: Negative divisor!
例外の再スロー
catch
ブロックで例外を処理した後、必要に応じて例外を再スローすることができます。これにより、上位の関数で再度例外処理を行うことが可能です。
#includeint divide(int a, int b) { if (b == 0) { throw std::runtime_error("Division by zero!"); } return a / b; } void safeDivide(int a, int b) { try { std::cout << "Result: " << divide(a, b) << std::endl; } catch (...) { std::cerr << "An error occurred, rethrowing the exception." << std::endl; throw; // 例外を再スロー } } int main() { int x = 10; int y = 0; try { safeDivide(x, y); } catch (const std::exception& e) { std::cerr << "Caught in main: " << e.what() << std::endl; } return 0; }
この例では、safeDivide
関数内で例外を捕捉し、再スローしています。main
関数内で再度その例外が捕捉され、最終的にエラーメッセージが表示されます。
An error occurred, rethrowing the exception. Caught in main: Division by zero!
まとめ
C++における例外処理は、プログラムのエラーハンドリングを柔軟に行うための強力なツールです。try
, catch
, throw
の基本的な使い方を理解し、例外を適切にキャッチして処理することで、エラー発生時のプログラムの安定性が向上します。さらに、例外の再スローや複数のcatch
ブロックを使い分けることで、より洗練されたエラーハンドリングが可能になります。例外処理をうまく活用し、堅牢なC++プログラムを作成しましょう。