C++
 Computer >> コンピューター >  >> プログラミング >> C++

【初心者向け】C++の例外処理の仕組みを徹底解説!try・catch・throwの基本から独自例外の作成まで

C++における例外処理(Exception Handling)とは、プログラムの実行中に発生するエラー(ランタイムエラー)を適切に処理するための仕組みです。例外とは、実行時に送出されるイベントのことを指し、C++ではすべての標準例外が std::exception クラスを基底クラスとして定義されています。

もし例外を捕捉しなければ、プログラムは例外メッセージを出力した後に異常終了してしまいます。例外はハンドリング可能なランタイムエラーであり、適切に処理することでプログラムの堅牢性を大きく向上させることができます。

標準例外クラスの階層構造

C++標準では、例外は <exception> ヘッダで定義されたクラス群として提供されており、プログラム内で自由に利用できます。親子関係によるクラス階層は以下のようになっています。

【初心者向け】C++の例外処理の仕組みを徹底解説!try・catch・throwの基本から独自例外の作成まで

主な標準例外クラスの一覧

No.例外クラスと説明
1std::exception
すべての標準C++例外の親となる基底クラスです。
2std::bad_cast
dynamic_cast が失敗した際に投げられる例外です。
3std::bad_exception
予期しない例外を処理するために使用される例外です。
4std::bad_alloc
new による動的メモリ確保の失敗時に投げられる例外です。
5std::logic_error
コードを読むだけで検出できる論理的な誤りを表す例外です。
6std::runtime_error
コードを読むだけでは検出できず、実行時にしか判明しないエラーを表す例外です。
7std::bad_typeid
typeid の使用時に投げられる例外です。

例外処理に使う3つのキーワード

C++の例外処理では、「try」「catch」「throw」という3つのキーワードを使用します。

  • throw:問題が発生したときに例外を送出します。
  • try:例外が発生する可能性のあるコードを囲みます。
  • catch:送出された例外を受け取り、処理を行います。

try / catch ブロックの基本

C++では、try/catch文を使って例外処理を行います。例外が発生する可能性のあるコードを try ブロック内に記述し、実際に例外が発生した場合には、対応する catch ブロックがそれを捕捉して処理します。

サンプルコード:例外発生時のオブジェクト破棄を確認する

#include <iostream>
using namespace std;

class Sample1 {
public:
    Sample1() {
        cout << "Construct an Object of sample1" << endl;
    }
    ~Sample1() {
        cout << "Destruct an Object of sample1" << endl;
    }
};

class Sample2 {
public:
    Sample2() {
        int i = 7;
        cout << "Construct an Object of sample2" << endl;
        throw i;
    }
    ~Sample2() {
        cout << "Destruct an Object of sample2" << endl;
    }
};

int main() {
    try {
        Sample1 s1;
        Sample2 s2;
    } catch(int i) {
        cout << "Caught " << i << endl;
    }
}

実行結果

Construct an Object of sample1
Construct an Object of sample2
Destruct an Object of sample1
Caught 7

この実行結果から重要な挙動が読み取れます。Sample2のコンストラクタ内で例外が送出されたため、それまでに構築が完了していたSample1のデストラクタが自動的に呼び出されています。これをスタック巻き戻し(stack unwinding)と呼びます。一方、コンストラクタが最後まで完了していないSample2のデストラクタは呼ばれない点にも注意しましょう。

ユーザー定義例外の作成方法

標準の例外クラスを継承し、その機能をオーバーライドすることで、独自の例外クラスを定義することもできます。

サンプルコード

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

struct DivideByZero : public exception {
    const char * what () const throw () {
        return "My Exception";
    }
};

int main() {
    try {
        throw DivideByZero();
    } catch(DivideByZero& e) {
        cout << "Exception caught" << endl;
        cout << e.what() << endl;
    } catch(exception& e) {
    }
}

実行結果

Exception caught
My Exception

what() メソッドとは

what() は例外クラスが提供する公開メソッドで、すべての子孫例外クラスによってオーバーライドされます。このメソッドは、例外が発生した原因を説明する文字列を返します。上記の例では、独自に定義したメッセージ「My Exception」が返されているのが確認できます。

  1. C++17のインライン変数(inline variable)とは?仕組みと使い方を解説

    C++では、関数に対してinlineキーワードを使用できます。そしてC++17からは、この概念が変数にも拡張され、「インライン変数(inline variable)」という新しい機能が導入されました。インライン変数の基本的な仕組みインライン変数は、複数の翻訳単位(translation unit)で定義することが許されている点が大きな特徴です。「1つの変数を複数回定義するとODR(One Definition Rule:一意定義ルール)に違反するのでは?」と思われるかもしれませんが、心配は不要です。インライン変数もODRに従っており、同じ変数が複数の翻訳単位で定義された場合でも、コンパイラとリ

  2. C++の例外処理入門!try・catch・throwの基本と標準例外クラス一覧

    C++における例外処理(Exception Handling)とは、プログラムの実行時に発生するエラー(ランタイムエラー)を適切に扱うための仕組みです。例外とは、実行時に送出(スロー)されるイベントのことで、C++ではすべての標準例外が std::exception クラスから派生しています。もし例外を捕捉しなかった場合、例外メッセージが出力され、プログラムは強制終了してしまいます。 C++標準では、例外関連のクラスが <exception> ヘッダに定義されており、プログラムの中で自由に利用できます。親子関係によるクラス階層は次のようになっています。 C++の主な標準例外クラス