6

C++ 標準では、例外をスローする with 関数の実行について次のように述べていstd::call_onceます (§30.4.4.2/2)。

2/ 効果: 関数を呼び出さない call_once の実行は、受動的な実行です。func を呼び出す call_once の実行は、アクティブな実行です。アクティブな実行は、INVOKE (DECAY_COPY (std::forward(func))、DECAY_COPY (std::forward(args))...) を呼び出す必要があります。このような func の呼び出しで例外がスローされた場合、実行は例外的であり、それ以外の場合は戻ります。例外的な実行は、call_once の呼び出し元に例外を伝播します。任意の once_flag に対する call_once のすべての実行の中で、最大で 1 つが実行を返す必要があります。戻る実行がある場合、それは最後のアクティブな実行になります。戻り実行がある場合にのみ、パッシブ実行があります。[ 注: パッシブ実行により、他のスレッドは、以前に返された実行によって生成された結果を確実に観察できます。— エンドノート]

Visual Studio 2012 を使用して、次のコードを実行しています。

void f(){
    throw std::exception( "Catch me!" );
}

int main( int argc, char* argv[] ){
    once_flag flag;
    try{
        call_once( flag, f );
    } catch( const std::exception& e ){
        cout << e.what() << endl;
    }
    return 0;
}

私の結果は次のとおりです。catch ブロック内のコードが実行され、メッセージが出力されますが、プログラムが存在する場合、呼び出しが行われabort()、次のメッセージが cout に出力されます。

...\mutex.c(38) ビジー中に破壊されたミューテックス

これは起こるはずですか?

4

1 に答える 1

7

これは起こるはずですか?

いいえ、そうではありません。これはバグです。

ただし、これについては VC11 だけではないことに注意してください。

  • Intel ICC 13.0.1 はstd::terminate()、例外が処理されなかったかのように呼び出します (実例を参照)。
  • GCC 4.8.0 ベータ版はおそらく似たようなことを行いますが、出力は表示されず、例外を飲み込んでプログラムをサイレントに終了します (実例を参照)。[更新: このバグは他の環境では再現できないようで、liveworkspace.org の構成のみに問題がある可能性があります]

一方、GCC 4.7.2 と Clang 3.2 は正しく動作します。

ちなみに、C++ 標準 (段落 18.8.1) では、std::exception にはデフォルト コンストラクターとコピー コンストラクターしかないと指定されていることに注意してください。使用しているコンストラクターは、移植性のない MS 拡張機能である可能性が最も高いです。

代わりに、文字列を受け入れるコンストラクターstd::logic_errorから派生してサポートするを使用することを検討してください。std::exception

于 2013-03-09T14:30:54.317 に答える