potisanのプログラミングメモ

プログラミング素人です。昔の自分を育ててくれたネット情報に少しでも貢献できるよう、情報を貯めていこうと思っています。Windows環境のC++やC#がメインです。

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;
}

参考