はじめに
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
と比較可能なスマートポインタの一種です。new
やdelete
は不要で、例外オブジェクトのメモリ管理を自動で行います。
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
を使って、例外をオブジェクトとして運び、任意の場所で再送出する方法を解説しました。
catch
ブロックの中でstd::current_exception()
を呼び出し、exception_ptr
を取得する。- 取得した
exception_ptr
を、別の関数やスレッドに渡す。 - 例外を処理したい場所で、
std::rethrow_exception()
を呼び出して、例外を再送出する。
この仕組みは、スレッドプールや非同期処理(std::async
など)の実装において、ワーカースレッドで発生したエラーを、呼び出し元のメインスレッドに適切に伝播させるための、不可欠な基盤技術となっています。