上記の質問は、次の 2 つのコード スニペットの動作を理解することに要約できます。
サンプル 1: アクティブな例外なしでスローする
int main()
{
try{
throw;
}catch(...){
std::cout<<"caught"<<endl; //we never reach here
}
return 0;
}
上記のコードを実行すると、以下のようにクラッシュします
terminate called without an active exception
Aborted (core dumped)
サンプル 2:アクティブな例外をスローする
int main()
{
try{
throw 7;
}catch(...){
std::cout<<"caught"<<endl; //will be caught
}
return 0;
}
それを実行すると、予測可能な出力が得られます
caught
コードのアセンブリを生成する場合 ( g++ -S option
)。throw と throw 7 の次の cxx_abi 呼び出しに気付くでしょう。
throw;
に変換されますcall __cxa_rethrow
と
throw 7;
に変換されますcall __cxa_throw
ここにコードがあります__cxa_throw
extern "C" void
__cxxabiv1::__cxa_throw (void *obj, std::type_info *tinfo,
void (_GLIBCXX_CDTOR_CALLABI *dest) (void *))
{
PROBE2 (throw, obj, tinfo);
__cxa_eh_globals *globals = __cxa_get_globals ();
globals->uncaughtExceptions += 1;
// code removed for brevity
//.......
// Below code throws an exception to be caught by caller
#ifdef _GLIBCXX_SJLJ_EXCEPTIONS
_Unwind_SjLj_RaiseException (&header->exc.unwindHeader);
#else
_Unwind_RaiseException (&header->exc.unwindHeader);
#endif
// Some sort of unwinding error. Note that terminate is a handler.
__cxa_begin_catch (&header->exc.unwindHeader);
std::terminate ();
}
そのため、OP コードでthrow 7;
は、対応することによってキャッチされ、によってcatch(...)
再スローされます。throw;
ここにコードがあります__cxa__rethrow
extern "C" void
__cxxabiv1::__cxa_rethrow ()
{
__cxa_eh_globals *globals = __cxa_get_globals ();
__cxa_exception *header = globals->caughtExceptions; // We are not re
globals->uncaughtExceptions += 1;
// Watch for luser rethrowing with no active exception.
if (header)
{
// Code removed for brevity
// .....
// Below code rethrows the exception
#ifdef _GLIBCXX_SJLJ_EXCEPTIONS
_Unwind_SjLj_Resume_or_Rethrow (&header->unwindHeader);
#else
#if defined(_LIBUNWIND_STD_ABI)
_Unwind_RaiseException (&header->unwindHeader);
#else
_Unwind_Resume_or_Rethrow (&header->unwindHeader);
#endif
#endif
}
std::terminate ();
}
std::terminate()
どちらの場合も、が からまだ呼び出されていないことがわかり__cxx_*
ます。上記の abi によってスローされた後、コード内の次の場所にいます。
コードを終了するには、 cxx_abiを参照してください。
void
__cxxabiv1::__terminate (std::terminate_handler handler) throw ()
{
__try
{
handler (); // Our handler has thrown an int exception
std::abort ();
}
__catch(...) // Exception is caught here and process is aborted.
{ std::abort (); }
}
void
std::terminate () throw()
{
__terminate (get_terminate ());
}
概要
私の理解によると、ハンドラーから例外を再スローすると、再スローされた例外が でキャッチされ__cxxabiv1::__terminate
ます。それが呼び出す場所abort()
。明らかに、std::terminate()
[from __cxa_rethrow] メソッドは登場しませんでした。それが、コントロールが到達しなかった理由です。 std::cout << "got here!" << std::endl;
無限再帰
terminate_handler を次のように変更するとどうなりますか。
void i_throw()
{
std::cout << "i_throw()" << std::endl;
throw;
std::cout << "got here!" << std::endl;
std::abort();
}
これを理解するために、__cxa_rethrow()
上記のように見ることができます。
スローされているアクティブな例外がないため、__cxa_rethrow()
呼び出しが終了しstd::terminate()
、無限再帰が発生します。