フリーキーズ | 独学プログラミング

初心者でもわかるC++の例外処理!try-catchの使い方入門編

最終更新日
リンドくん

リンドくん

たなべ先生、C++でプログラムを書いていると時々エラーで止まってしまうんです。
エラーが起きてもプログラムが落ちないようにする方法ってあるんですか?

たなべ

たなべ

いい質問だね!それこそが例外処理(エクセプション・ハンドリング)の出番なんだ。
C++では
try-catch文
を使って、エラーが発生してもプログラムが安全に動き続けるような仕組みを作ることができるよ。

プログラミングを学び始めて少し経つと、必ず直面するのが「エラーの処理」という問題です。
特にC++のような低レベルなプログラミング言語では、メモリ不足やファイルの読み書きエラーなど、さまざまな予期しない問題が発生する可能性があります。

そんなとき、プログラムが突然終了してしまったり、不正な動作をしてしまったりすることを防ぐために重要な技術が例外処理です。
この記事では、C++の例外処理の基本的な概念から実践的な使い方まで、プログラミング初心者の方でも理解できるよう段階的に解説していきます。

例外処理とは何か

リンドくん

リンドくん

そもそも「例外」って何なんですか?普通のエラーとは違うんですか?

たなべ

たなべ

例外はプログラムの実行中に発生する予期しない問題のことなんだ。
普通のエラーと違って、プログラムを止めずに適切に対処できるのが特徴なんだよ。

例外処理の基本概念

例外処理とは、プログラムの実行中に発生するエラーや異常な状況を適切に処理する仕組みのことです。
従来のエラー処理では、関数の戻り値でエラーコードを返すという方法が一般的でしたが、例外処理はより柔軟で強力な仕組みを提供します。

例外処理の主なメリットは以下のとおりです。

  • プログラムの安全性向上 → エラーが発生してもプログラムが突然終了することを防げます
  • エラー処理の集約 → 複数のエラーを一箇所でまとめて処理できます
  • コードの可読性向上 → 通常の処理とエラー処理を分離できます
  • デバッグの効率化 → エラーの詳細情報を取得しやすくなります

例外が発生する典型的なケース

C++プログラムで例外が発生する代表的なケースは以下のような場面があります。

  • メモリ不足new演算子でメモリ確保に失敗した場合
  • 配列の範囲外アクセス → 配列のサイズを超えたインデックスにアクセスした場合
  • ファイル操作エラー → 存在しないファイルを開こうとした場合
  • 数値計算エラー → ゼロ除算など不正な計算を行った場合

これらの問題が発生したとき、例外処理を使わないプログラムは突然終了してしまいますが、適切に例外処理を実装することで、エラーメッセージを表示してから安全にプログラムを続行することができます。

try-catch文の基本的な書き方と構文

基本的な構文

C++の例外処理の基本となるのがtry-catch文です。
基本的な構文は以下のようになります。

try
{
    // 例外が発生する可能性のあるコード
    // 通常の処理を記述
}
catch (例外の型 変数名)
{
    // 例外が発生した時の処理
    // エラーハンドリングを記述
}

具体的な使用例

実際のコードで見てみましょう。

#include <iostream>
#include <stdexcept>

int main()
{
    try
    {
        int number;
        std::cout << "数値を入力してください: ";
        std::cin >> number;
        
        if (number == 0)
        {
            // 例外を投げる
            throw std::runtime_error("ゼロは処理できません");
        }
        
        int result = 100 / number;
        std::cout << "100 ÷ " << number << " = " << result << std::endl;
        
    }
    catch (const std::runtime_error& e)
    {
        // 例外をキャッチして処理
        std::cout << "エラーが発生しました: " << e.what() << std::endl;
    }
    
    std::cout << "プログラムは正常に続行されます" << std::endl;
    return 0;
}

このコードでは、ユーザーがゼロを入力した場合に例外を投げ、catch文でそれをキャッチしてエラーメッセージを表示しています。
プログラムが突然終了することなく、適切にエラーを処理できています。

複数の例外をキャッチする方法

異なる種類の例外に対して個別の処理を行いたい場合は、複数のcatch文を使用できます。

try
{
    // 何らかの処理
}
catch (const std::bad_alloc& e)
{
    // メモリ不足エラーの処理
    std::cout << "メモリが不足しています" << std::endl;
}
catch (const std::out_of_range& e)
{
    // 範囲外アクセスエラーの処理
    std::cout << "配列の範囲外にアクセスしました" << std::endl;
}
catch (const std::exception& e)
{
    // その他の標準例外の処理
    std::cout << "予期しないエラー: " << e.what() << std::endl;
}

標準例外クラスの種類と使い分け

リンドくん

リンドくん

C++にはどんな種類の例外があるんですか?自分で作ることもできるんですか?

たなべ

たなべ

C++には標準ライブラリで提供される例外クラスがたくさんあるんだ。
もちろん自分で独自の例外クラスを作ることもできるよ。用途に応じて使い分けることが大切なんだ。

主要な標準例外クラス

C++標準ライブラリには、様々な状況に対応した例外クラスが用意されています。

基本的な例外クラス

  • std::exception → すべての標準例外の基底クラス
  • std::runtime_error → 実行時エラー全般
  • std::logic_error → プログラムのロジックエラー

具体的な例外クラス

  • std::bad_alloc → メモリ確保の失敗
  • std::out_of_range → 範囲外アクセス
  • std::invalid_argument → 不正な引数
  • std::overflow_error → 数値オーバーフロー

実践的な使用例

各例外クラスの使い方を実際のコードで見てみましょう。

#include <iostream>
#include <vector>
#include <stdexcept>

void demonstrateExceptions()
{
    try
    {
        // 1. out_of_range例外の例
        std::vector<int> numbers = {1, 2, 3, 4, 5};
        std::cout << numbers.at(10) << std::endl;  // 範囲外アクセス
        
    }
    catch (const std::out_of_range& e)
    {
        std::cout << "範囲外アクセスエラー: " << e.what() << std::endl;
    }
    
    try
    {
        // 2. invalid_argument例外の例
        int age = std::stoi("abc");  // 文字列を数値に変換(失敗)
        
    }
    catch (const std::invalid_argument& e)
    {
        std::cout << "不正な引数エラー: " << e.what() << std::endl;
    }
    
    try
    {
        // 3. bad_alloc例外の例(大量メモリ確保)
        int* huge_array = new int[SIZE_MAX];  // 巨大な配列確保
        
    }
    catch (const std::bad_alloc& e)
    {
        std::cout << "メモリ不足エラー: " << e.what() << std::endl;
    }
}

カスタム例外クラスの作成

独自の例外クラスを作成することで、より具体的で意味のあるエラー処理が可能になります。

#include <iostream>
#include <exception>
#include <string>

// カスタム例外クラス
class InvalidAgeException : public std::exception
{
private:
    std::string message;
    
public:
    InvalidAgeException(int age)
    {
        message = "無効な年齢です: " + std::to_string(age);
    }
    
    const char* what() const noexcept override
    {
        return message.c_str();
    }
};

void checkAge(int age)
{
    if (age < 0 || age > 150)
    {
        throw InvalidAgeException(age);
    }
    std::cout << "年齢 " << age << " は有効です" << std::endl;
}

int main()
{
    try
    {
        checkAge(200);  // 無効な年齢
    }
    catch (const InvalidAgeException& e)
    {
        std::cout << "カスタムエラー: " << e.what() << std::endl;
    }
    
    return 0;
}

この例では、年齢の妥当性をチェックする独自の例外クラスを作成しています。
プログラムの意図が明確になり、デバッグも効率的に行えます。

まとめ

リンドくん

リンドくん

例外処理って奥が深いんですね!でも覚えることで、プログラムがずっと安全になりそうです。

たなべ

たなべ

その通り!例外処理をマスターすることで、プロレベルのC++プログラマに一歩近づけるよ。
最初は難しく感じるかもしれないけど、実際に使っていけば必ず身につくからね。

この記事では、C++の例外処理について基本概念から実践的な使い方まで解説してきました。
例外処理は、単なるエラーハンドリングの技術を超えて、安全で信頼性の高いソフトウェアを作るための重要な基盤技術です。

重要なポイントのおさらい

  • try-catch文でプログラムの安全性を大幅に向上させることができます
  • 標準例外クラスを適切に使い分けることで、具体的で意味のあるエラー処理が可能になります
  • カスタム例外クラスを作成することで、プログラムの意図をより明確に表現できます
  • RAIIとの組み合わせにより、リソースの安全な管理が実現できます

例外処理をマスターすることで、あなたのC++プログラミングスキルは確実に次のレベルに達するでしょう。
今後のプロジェクトでは、ぜひ積極的に例外処理を活用してみてください。

関連するコンテンツ