VC++の例外処理の仕組みを追う その4
今度は退避しておいた例外オブジェクトの再スローです。
例外を送出するには、
- スタックに例外オブジェクトのサイズ分の領域を確保する
- コピーコンストラクタを呼び出して例外オブジェクトを初期化する
- _CxxThrowException()を呼ぶ
という手順を踏むことになります。
これをそのまま実装するとこうなります。
#include <cstring> #include <malloc.h> // for _alloca() // 例外オブジェクトdataを例外情報infoに従って送出する __declspec(noreturn) void rethrow(void* data, const _s__ThrowInfo* info) { const _s__CatchableType* t = info->pCatchableTypeArray->arrayOfCatchableTypes[0]; int sz = t->sizeOrOffset; _PMFN cp = t->copyFunction; void* e = _alloca(sz); if (cp) call_pmfn1(cp, e, data); else std::memcpy(e, data, sz); _CxxThrowException(e, info); throw; // 最適化防止のためのダミー }
最後のthrowがないと、rethrow()は例外を投げない関数と判断され、最適化の結果、呼び出し側のcatch節が無視されるようです。
「throw 0」とかでも動きますが、将来のバージョンでint以外のcatch節が無視される可能性もあるため、再スローを使いました。
再スローならあらゆる型を送出する可能性があるので安心です。
(が、もっと賢いコンパイラなら再スローするものがないことを検出するかもしれません。)