VC++の例外処理の仕組みを追う その3

catchした任意のオブジェクトをコピーするところまで出来ました。

#include <windows.h>

extern "C"
{

// CRTのTLSデータ
struct _tiddata;
_tiddata* __cdecl _getptd();

} // extern "C"

// C++例外を示すコード
const ::DWORD cxx_exception_code = 0xE06D7363;

// 捕捉中の例外レコードを取得する
const ::EXCEPTION_RECORD* get_current_exception_record()
{
    _tiddata* p = _getptd();
#if _MSC_VER < 1400
    return reinterpret_cast< ::EXCEPTION_RECORD**>(p)[31];
#else
    return reinterpret_cast< ::EXCEPTION_RECORD**>(p)[34];
#endif
}

// 0引数のメンバ関数を呼ぶ
inline void call_pmfn0(_PMFN f, void* p)
{
    if (f)
    {
        __asm
        {
            mov ecx, p
            call f
        }
    }
}

// 1引数のメンバ関数を呼ぶ
inline void call_pmfn1(_PMFN f, void* p0, void* p1)
{
    if (f)
    {
        __asm
        {
            mov ecx, p0
            push p1
            call f
        }
    }
}


// ここからお試しコード
#include <iostream>

struct my_exception
{
    int a;

    my_exception()
    {
        std::cout << "construct: " << static_cast<void*>(this) << std::endl;
    }

    my_exception(const my_exception&)
    {
        std::cout << "copy: " << static_cast<void*>(this) << std::endl;
    }

    ~my_exception()
    {
        std::cout << "destruct: " << static_cast<void*>(this) << std::endl;
    }

    my_exception& operator=(const my_exception&)
    {
        std::cout << "assign: " << static_cast<void*>(this) << std::endl;
        return *this;
    }
};

int main()
{
    void* e = 0;
    _PMFN d = 0;

    try
    {
        throw my_exception();
    }
    catch (...)
    {
        const ::EXCEPTION_RECORD* er = get_current_exception_record();
        if (er)
        {
            if (er->ExceptionCode == cxx_exception_code)
            {
                // 例外オブジェクト
                void* data =
                    reinterpret_cast<void*>(er->ExceptionInformation[1]);

                // 例外情報
                _s__ThrowInfo* ti =
                    reinterpret_cast<_s__ThrowInfo*>(
                        er->ExceptionInformation[2]
                    );

                // 多分0番目が最派生クラス
                const _s__CatchableType* t =
                    ti->pCatchableTypeArray->arrayOfCatchableTypes[0];

                e = ::operator new(t->sizeOrOffset);
                // FIXME: 例外安全じゃない
                call_pmfn1(t->copyFunction, e, data);
                d = ti->pmfnUnwind;
            }
        }
    }

    std::cout << "-----------------"<< std::endl;

    if (e)
    {
        call_pmfn0(d, e);
        ::operator delete(e);
    }

    return 0;
}

結果はこんな感じです。

construct: 0012FF20
copy: 009F7F10
destruct: 0012FF20

                                • -

destruct: 009F7F10