モーダルを閉じる工作HardwareHub ロゴ画像

工作HardwareHubは、ロボット工作や電子工作に関する情報やモノが行き交うコミュニティサイトです。さらに詳しく

利用規約プライバシーポリシー に同意したうえでログインしてください。

工作HardwareHub ロゴ画像 (Laptop端末利用時)
工作HardwareHub ロゴ画像 (Mobile端末利用時)

例外 (C++をもう一度)

モーダルを閉じる

ステッカーを選択してください

モーダルを閉じる

お支払い内容をご確認ください

購入商品
」ステッカーの表示権
メッセージ
料金
(税込)
決済方法
GooglePayマーク
決済プラットフォーム
確認事項

利用規約をご確認のうえお支払いください

※カード情報はGoogleアカウント内に保存されます。本サイトやStripeには保存されません

※記事の執筆者は購入者のユーザー名を知ることができます

※購入後のキャンセルはできません

作成日作成日
2014/12/14
最終更新最終更新
2021/10/07
記事区分記事区分
一般公開

目次

    低レイヤーのプログラミングとOS開発が趣味。C言語を使っています。

    0
    ステッカーを贈るとは?

    基本的な構文

    #include <iostream>
    #include <cstdlib>
    using namespace std;
    
    void MyFunc() {
        if(true) {
            throw "MyFunc";
        }
        // 正常時の処理...
    }
    
    int main() {
    
        try {
            if (true) { // エラー判定
                throw "main";
                // throw 1;
            }
    
            // 関数内からもthrowできます
            MyFunc();
    
            // 正常時の処理...
        }
        catch (const char* error) { // throwされた値
            // エラー時の処理
            // (↑tryでのみ有効なオブジェクトのデストラクタは、抜ける際に実行済みです)
            cerr << "const char*: " << error << endl;
            return EXIT_FAILURE;
        }
        catch (int error) { // intがthrowされた場合
            try { // 入れ子にできます
                if(true) {
                    throw "nested try-catch";
                }
                cerr << "int: " << error << endl;
                return EXIT_FAILURE;
            }
            catch (const char* error) {
                cerr << "const char*: " << error << endl;
                return EXIT_FAILURE;
            }
        }
        catch (...) { // 対応するcatchがないthrowの場合
            return EXIT_FAILURE;
        }
    
        return 0;
    }
    

    例外指定子

    #include <iostream>
    #include <cstdlib>
    using namespace std;
    
    void MyFunc() throw() { // 例外指定 (← 実用性は低いですが知識として)
        // MyFunc は例外を何も投げない throw() と宣言しているため
        throw 1; // とするとエラーになります
    }
    
    int main() {
        try {
            MyFunc();
        }
        catch (...) {
            return EXIT_FAILURE;
        }
        return 0;
    }
    

    catch節内でthrowする構文

    異なる型の例外をthrowする可能性がある場合

    #include <iostream>
    using namespace std;
    
    void MyFunc() {
        try {
            throw 1;
        }
        catch (int error) {
            throw "MyFunc";
        }
        catch (const char* error) {
            cerr << "同階層のものは実行されず" << endl;
        }
    }
    
    int main() {
        try {
            MyFunc();
        }
        catch (const char* error) {
            cerr << "1つ外のものが実行されます" << endl;
        }
        return 0;
    }
    

    同じ型の例外をthrowすることが確定している場合の特別構文

    #include <iostream>
    using namespace std;
    
    void MyFunc() {
        try {
            throw "MyFunc";
            // throw 1; // int型のthrow
        }
        catch (...) {
            // どのような型のthrowであっても必ず行う必要のある
            // 汎用性の高い処理を記述。メモリ解放など。
            cerr << "caught at MyFunc" << endl;
    
            throw; // exception rethrow (例外の再送出)
        }
    }
    
    int main() {
        try {
            MyFunc();
        }
        catch (const char* error) {
            cerr << "const char*: " << error << endl;
        }
        catch (int error) {
            cerr << "int: " << error << endl;
        }
        return 0;
    }
    

    クラス型の例外をthrow

    例外は基本型ではなくクラスにするのが通常です。その理解のためにはアップキャストの知識などが必要です。

    #include <iostream>
    #include <string>
    #include <cstdlib>
    
    class MyException {
    public:
        MyException(const char* error);
        virtual ~MyException(); // 仮想デストラクタ
    
    public:
        const char* What() const;
    
    protected:
        std::string m_error;
    };
    
    class MySubException :
        public MyException
    {
    public:
        MySubException(const char* str);
    };
    
    using namespace std;
    
    MyException::MyException(const char* error) :
        m_error(error)
    {
    }
    
    MyException::~MyException() {
    }
    
    const char* MyException::What() const {
        return m_error.c_str();
    }
    
    MySubException::MySubException(const char* str) :
        MyException("MySubException")
    {
        m_error += ": ";
        m_error += str;
    }
    
    int main() {
        try {
            throw MySubException("main");
        }
        catch (const MyException& e) { // アップキャスト
            cerr << e.What() << endl; //=> MySubException: main
            return EXIT_FAILURE;
        }
        return 0;
    }
    

    コンストラクタで例外を投げる

    #include <iostream>
    #include <cstdlib>
    using namespace std;
    
    class MyClass {
    public:
        MyClass();
        ~MyClass();
    };
    
    MyClass::MyClass() {
        cout << "MyClass::MyClass" << endl;
        // メモリ確保 new していたとしても
        throw exception();
        // ↑標準例外クラスを使用しています
        // - exception() すべての例外クラスの基底
        // - logic_error() コンパイル時に検出可能な例外クラスの基底 (exception() の派生クラス)
        //   - invalid_argument() 不正な引数
        //   - ..等
        // - runtime_error() 実行時に検出可能な例外クラスの基底 (exception() の派生クラス)
        //   - overflow_error() オーバーフロー
        //   - ..等
        // - その他 (bad_*)
        //   - bad_alloc() メモリ確保に失敗
        //   - ..等
    }
    
    MyClass::~MyClass() {
        // コンストラクタが完了する前に例外が投げられたため
        // デストラクタは実行されない。つまり
        // 解放 delete できない (メモリリークの原因の一つ)
        cout << "MyClass::~MyClass" << endl;
    }
    
    int main() {
        try {
            MyClass obj; //=> MyClass::MyClass
                         // (MyClass::~MyClass は表示されない)
        }
        catch (...) {
            return EXIT_FAILURE;
        }
        return 0;
    }
    

    デストラクタで例外を投げる

    #include <iostream>
    #include <cstdlib>
    using namespace std;
    
    class MyClass {
    public:
        MyClass();
        ~MyClass();
    };
    
    MyClass::MyClass() {
        cout << "MyClass::MyClass" << endl;
    }
    
    MyClass::~MyClass() {
        cout << "MyClass::~MyClass" << endl;
        throw exception();
    
        // デストラクタ内で例外が発生するような
        // 操作を行うべきでない <*1↓>
        // (発生してしまう場合でも以下のように
        //  デストラクタ内で処理することが必要です)
        // try {
        //     throw exception();
        // }
        // catch (const exception& e) {
        //     // メモリ解放などの処理
        // }
    }
    
    int main() {
        try {
            MyClass obj;
            throw exception(); // ここで投げられた例外を処理して
        }
        catch (...) {
            // ここに処理を移動させようとすると
            // obj のデストラクタが実行されて
            // 二重例外 (→エラーになります) が発生します <*1>
            return EXIT_FAILURE;
        }
        return 0;
    }
    
    0
    詳細設定を開く/閉じる
    アカウント プロフィール画像 (本文下)

    低レイヤーのプログラミングとOS開発が趣味。C言語を使っています。

    記事の執筆者にステッカーを贈る

    有益な情報に対するお礼として、またはコメント欄における質問への返答に対するお礼として、 記事の読者は、執筆者に有料のステッカーを贈ることができます。

    さらに詳しく →
    ステッカーを贈る コンセプト画像

    Feedbacks

    Feedbacks コンセプト画像

      ログインするとコメントを投稿できます。

      関連記事