potisanのプログラミングメモ

趣味のプログラマーがプログラミング関係で気になったことや調べたことをいつでも忘れられるようにメモするブログです。はてなブログ無料版なので記事の上の方はたぶん広告です。記事中にも広告挿入されるみたいです。

C++ Function-try-block(関数tryブロック)

関数tryブロック

WILのGitHub Wikiを読んでいたら関数名の後ろ、constnoexceptのある部分にtry、関数の直後にcatchのあるコードを見かけました。main関数で示せば次のような感じです。

#include <exception>

int main() try
{
    throw std::exception();
}
catch (...)
{
    return 1234;
}

上記の構文はFunction-try-block(関数tryブロック)というそうです。mainで発生した未捕捉の例外はmain直後のcatch文で捕捉されます。上のコードは終了コード1234で正常終了します。

WILでの利用

例外の捕捉コストはある気がしますが、WILでは例外をHRESULTへ変換したりその逆を行うマクロなどで使用されています。関数内に毎回try-catchを書くより、関数名後ろのtryとブロック直後のマクロを書く方がたしかに簡潔だと思います。

MSVCのコンストラクタにおける不思議な挙動

MSVC(Visual Studio C++ 2019)では不思議な挙動がありました。コンストラクタ内部で発生した例外は呼び出し側がtryを使っている場合は関数tryブロックでも適切に処理され、tryを使っていない場合はコンストラクタ内部のthrowで強制終了しました。コンストラクタやデストラクタはそもそも例外を伝播させない設計が求められていたと思うので、使用時は注意が必要かもしれません。

#include <exception>
#include <iostream>

struct test_class {
    test_class() try {
        throw std::exception();
    } catch (...) {
        std::cout << "test_class::test_class() function-try-block" << std::endl;
    }
};

int main()
{
    try {
        test_class t;
    } catch (...) {
        std::cout << "main() function-try-block" << std::endl;
    }
    // 出力:
    // test_class::test_class() function-try-block
    // main() function - try - block

    test_class t;
    // 出力:
    // ※test_class::test_class()のthrow行でハンドルされない例外により強制終了。

    return 0;
}

参考