2016年9月26日月曜日

[Visual C++] lambda を使った構造化例外と C++ 例外の処理

VC++ には構造化例外処理(Structured Exception Handling、通称SEH)があります。
これは C++ の try - catch とは別に __try - __except で処理することができます。

さて、この独自拡張で問題になること、というかメンドクサイことナンバーワンは、
1つの関数で try と __try を同時に使えないことではないでしょうか?

つまり、こういうことです。
void f()
{
    try {
        __try {  // error C2713: 関数ごとに許されている例外ハンドルのフォームは 1 つです。
        } __except(EXCEPTION_EXECUTE_HANDLER) {
        }
    } catch(...) {
    }
}

void g()
{
    __try {
    } __except(EXCEPTION_EXECUTE_HANDLER) {
    }

    try { // error C2713: 関数ごとに許されている例外ハンドルのフォームは 1 つです。
    } catch(...) {
    }
}
void fa()
{
    __try {
    } __except(EXCEPTION_EXECUTE_HANDLER) {
    }
}
void fb()
{
    try {
        fa(); // OK
    } catch(...) {
    }
}

lambda があるじゃない
Visual Studio でも lambda が使えるようになってます。これ使えばわざわざ関数にしなくても済みます!

void f()
{
    try {
        []() {
            __try {}
      __except(EXCEPTION_EXECUTE_HANDLER) {}
        }();
    } __except(EXCEPTION_EXECUTE_HANDLER) {
    }
}

やったね!

とはならない…

VS2012/2013 でエラー
上記コードは VS2015 なら問題なくビルドできます
しかし、VS2012/2013 ではエラーとなってしまいます。
(エラー内容は lambda 使う前と同じ、「error C2713: 関数ごとに許されている例外ハンドルのフォームは 1 つです。」)

もう少し詳しく書くと、こう。

void f()
{
    __try {
        []() {
            try {}
            catch( ... ) {}
        }();
    } __except( EXCEPTION_EXECUTE_HANDLER ) {
    }
}

void g()
{
    try {
        []() {
            __try {} // error C2713: 関数ごとに許されている例外ハンドルのフォームは 1 つです。
            __except( EXCEPTION_EXECUTE_HANDLER ) {}
        }();
    } catch( ... ) {
    }
}

void h()
{
    auto x = []() {
        __try {}
        __except( EXCEPTION_EXECUTE_HANDLER ) {}
    };
    try {
        x();
    } catch( ... ) {
    }
}

__try の中に try がある場合は OK
try の中に __try があるのは NG
lambda が try の外で定義されいれば OK

という感じでした。

まとめ
Visual Studio 2015 を使おう!

0 件のコメント:

コメントを投稿