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節が無視される可能性もあるため、再スローを使いました。
再スローならあらゆる型を送出する可能性があるので安心です。
(が、もっと賢いコンパイラなら再スローするものがないことを検出するかもしれません。)