【C++】std::exception_ptrで例外を保存・再送出する方法

目次

はじめに

C++の例外処理では、catchブロックで例外を捕捉すると、その場で処理するのが基本です。しかし、特にマルチスレッドプログラミングなどでは、「ワーカースレッドで発生した例外を、メインスレッドに伝えて、そこで処理させたい」という場面があります。

この「スレッドをまたいで例外を運ぶ」という要求に応えるのが、C++11で導入された**std::exception_ptrです。exception_ptrを使うと、catchブロックで捕捉した例外を、一旦オブジェクトとして保持し、好きなタイミング、好きな場所(別のスレッドなど)で、あたかも元々そこで発生したかのように再送出(rethrow)**することができます。


【前提】C++11とは?

C++11は、2011年に正式化されたC++言語のメジャーアップデート版です。exception_ptrはこのC++11で導入されたため、利用するにはC++11以降に対応したコンパイラが必要です。


exception_ptr を使ったサンプルコード

このコードは、try-catchブロックの中でstd::current_exceptionを使って現在の例外をexception_ptrに保存し、その後、別の場所でstd::rethrow_exceptionを使ってその例外を再送出します。

完成コード

#include <iostream>
#include <exception> // exception_ptr, current_exception, rethrow_exception
#include <stdexcept> // runtime_error
#include <string>

using namespace std;

int main() {
    exception_ptr e_ptr = nullptr; // 例外を保持するためのポインタ

    // --- 1. 例外を捕捉し、exception_ptrに保存 ---
    try {
        throw runtime_error("元のエラーメッセージ");
    }
    catch (...) { // ... は、あらゆる種類の例外を捕捉する
        // current_exception()で、現在処理中の例外を取得
        e_ptr = current_exception();
        cout << "例外を捕捉し、exception_ptrに保存しました。" << endl;
    }
    
    // e_ptrが有効な例外を指しているか確認
    if (e_ptr) {
        cout << "e_ptrは有効な例外を指しています。" << endl;
    }

    // --- 2. 保存した例外を、別の場所で再送出 ---
    if (e_ptr) {
        try {
            cout << "\n保存した例外を再送出します..." << endl;
            // rethrow_exception()で、保存した例外を再送出
            rethrow_exception(e_ptr);
        }
        catch (const runtime_error& e) {
            // 再送出された例外を、具体的な型で捕捉
            cout << "再送出された例外を捕捉しました: " << e.what() << endl;
        }
    }

    return 0;
}

コードの解説

1. std::exception_ptr

<exception>ヘッダーで提供される、nullptrと比較可能なスマートポインタの一種です。newdeleteは不要で、例外オブジェクトのメモリ管理を自動で行います。

2. std::current_exception()

catchブロックの内部でのみ呼び出すことができます。現在処理中の例外オブジェクトへのexception_ptrを返します。catch (...)のように、例外の型が分からなくても、例外そのものを取得できるのが特徴です。

3. std::rethrow_exception(e_ptr)

引数で渡されたexception_ptrが指す例外を、その場で再送出します。再送出された例外は、通常のtry-catchブロックで、元の型(この例ではruntime_error)として捕捉できます。


まとめ

今回は、C++11のstd::exception_ptrを使って、例外をオブジェクトとして運び、任意の場所で再送出する方法を解説しました。

  1. catchブロックの中で std::current_exception() を呼び出し、exception_ptrを取得する。
  2. 取得したexception_ptrを、別の関数やスレッドに渡す。
  3. 例外を処理したい場所で、std::rethrow_exception() を呼び出して、例外を再送出する。

この仕組みは、スレッドプールや非同期処理(std::asyncなど)の実装において、ワーカースレッドで発生したエラーを、呼び出し元のメインスレッドに適切に伝播させるための、不可欠な基盤技術となっています。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次