C++例外処理

こんにちは、夢を持つプログラマーの皆さん!今日、私たちはC++例外処理のワクワクする旅に出かけます。あなたの親しみのある近所のコンピュータサイエンスの先生として、私はあなたをこの重要なトピックを通じてガイドします。だから、お気に入りの飲み物を持って、快適に座り、一緒に飛び込みましょう!

C++ Exception Handling

例外とは何か?

まず、私たちが熟練したジャグラーのように例外を投げたりキャッチしたりする前に、それが何か理解しましょう。プログラミングの世界では、例外はプログラムの実行中に発生する予期せぬイベントです。それは私がかつてやっていた驚きのポップクイズのようです(それについては申し訳ありません!)、予期せずて、時には扱いにくいものです。

例外は、プログラムの指示の通常の流れを中断します。それは、さまざまな要因によって引き起こされることがあります。例えば:

  1. ゼロ除算
  2. 配列の範囲外へのアクセス
  3. メモリ不足
  4. 存在しないファイルを開こうとする

では、C++がこれらの予期せぬ状況をどのように美しく管理できるかを見ていきましょう。

例外の投げ方

投げ方の基本

C++では、throwキーワードを使って例外を発生させます。それは、クラスで質問や問題があるときに手を挙げるのと同じです。以下は簡単な例です:

#include <iostream>
using namespace std;

int main() {
try {
throw 20;
}
catch (int e) {
cout << "例外が発生しました。例外番号:" << e << endl;
}
return 0;
}

この例では、私たちは整数例外を値20で投げています。でも大丈夫、今すぐキャッチします!

異なる型の投げ方

C++は柔軟で、さまざまな型の例外を投げることができます。もっと実用的な例を見てみましょう:

#include <iostream>
#include <stdexcept>
using namespace std;

double divide(int a, int b) {
if (b == 0) {
throw runtime_error("ゼロ除算です!");
}
return static_cast<double>(a) / b;
}

int main() {
try {
cout << divide(10, 2) << endl;  // これは問題ありません
cout << divide(10, 0) << endl;  // これは例外を投げます
}
catch (const runtime_error& e) {
cout << "例外をキャッチしました: " << e.what() << endl;
}
return 0;
}

この例では、誰かがゼロ除算を試みたときにruntime_error例外を投げています。それは、私たちの数学的な近所に「ゼロ除算禁止」のサインを立てるようなものです!

例外のキャッチ方

キャッチ方の基本

今や私たちは例外を投げる方法を知っていますが、それをキャッチする方法を学びましょう。例外をキャッチすることは、責任あるペットの飼い主のようなものです - あなたのコードがあなたに何を投げようとしても、対処する準備ができている必要があります!

私たちはtry-catchブロックを使って例外をキャッチします。tryブロックには例外が投げられるコードが含まれ、catchブロックは例外が発生した場合にそれを処理します。

#include <iostream>
using namespace std;

int main() {
try {
int age = -5;
if (age < 0) {
throw "年齢が負けません!";
}
cout << "年齢は:" << age << endl;
}
catch (const char* msg) {
cerr << "エラー: " << msg << endl;
}
return 0;
}

この例では、年齢が負かどうかをチェックしています。もしそうなら、カスタムエラーメッセージとともに例外を投げます。

複数の例外のキャッチ方

時に、同じコードから異なる型の例外が投げられることがあります。その場合、複数のcatchブロックを持つことができます:

#include <iostream>
#include <stdexcept>
using namespace std;

int main() {
try {
int choice;
cout << "整数例外に1、ランタイムエラーに2を入力してください: ";
cin >> choice;

if (choice == 1) {
throw 42;
} else if (choice == 2) {
throw runtime_error("野生のランタイムエラーが現れた!");
} else {
throw "不明な選択です!";
}
}
catch (int e) {
cout << "整数例外をキャッチしました: " << e << endl;
}
catch (const runtime_error& e) {
cout << "ランタイムエラーをキャッチしました: " << e.what() << endl;
}
catch (...) {
cout << "不明な例外をキャッチしました!" << endl;
}
return 0;
}

この例では、異なる型の例外をキャッチする方法を示しています。catch (...)ブロックは、前のcatchブロックによってキャッチされなかったすべての例外を処理するための安全ネットのようなものです!

C++標準例外

C++には、プログラムで使用できる標準例外のセットがあります。これらは、例外の世界でのスイスアーミーナイフのように、多様で常に役立ちます!

以下は、一般的に使用される標準例外の一部です:

例外 説明
std::runtime_error ランタイムロジックエラー
std::logic_error ロジックエラー
std::out_of_range 範囲外へのアクセス
std::overflow_error 算術オーバーフロー
std::bad_alloc メモリ割り当てが失敗

標準例外を使用する例を見ていきましょう:

#include <iostream>
#include <vector>
#include <stdexcept>
using namespace std;

int main() {
vector<int> numbers = {1, 2, 3, 4, 5};
try {
cout << numbers.at(10) << endl;  // これはout_of_range例外を投げます
}
catch (const out_of_range& e) {
cerr << "範囲外エラー: " << e.what() << endl;
}
return 0;
}

この例では、ベクターの範囲外にアクセスしようとすると、at()関数がout_of_range例外を投げます。

新しい例外の定義

標準例外は素晴らしいですが、特定のニーズに合わせてカスタム例外が必要になることもあります。そんなときに便利なのが、カスタム例外です!

以下は、独自の例外クラスを定義する方法です:

#include <iostream>
#include <exception>
using namespace std;

class NegativeValueException : public exception {
public:
const char* what() const throw() {
return "負の値は許可されません!";
}
};

double squareRoot(double x) {
if (x < 0) {
throw NegativeValueException();
}
return sqrt(x);
}

int main() {
try {
cout << squareRoot(25) << endl;  // これは問題ありません
cout << squareRoot(-5) << endl;  // これは私たちのカスタム例外を投げます
}
catch (const NegativeValueException& e) {
cerr << "エラー: " << e.what() << endl;
}
return 0;
}

この例では、NegativeValueExceptionクラスを作成しました。私たちは、squareRoot関数で負の数の平方根を計算しようとするときにそれを投げます。

それでは、皆さん!C++例外処理の基本についてお話ししました。例外はあなたの友であり、より堅牢でエラーに対応したコードを書くのに役立ちます。練習を続けることで、プロのように例外を処理することができるようになります!

コーディングを楽しんで、あなたの例外はいつもキャッチされますように!

Credits: Image by storyset