web-dev-qa-db-ja.com

C ++ではスロー後にデストラクタが呼び出されますか?

サンプルプログラムを実行し、実際にスタックに割り当てられたオブジェクトのデストラクタが呼び出されましたが、これは標準で保証されていますか?

47
Luchian Grigore

はい、それは保証されています(例外がキャッチされた場合)、デストラクタが呼び出されるthe orderまで:

C++ 1115.2コンストラクタとデストラクタ[except.ctor]

1制御がスロー式からハンドラーに渡されると、tryブロックに入った後に作成されたすべての自動オブジェクトに対してデストラクタが呼び出されます。自動オブジェクトは、構築の完了とは逆の順序で破棄されます。

さらに、オブジェクトの構築中に例外がスローされた場合、部分的に構築されたオブジェクトのサブオブジェクトが正しく破棄されることが保証されています。

2例外によって初期化または破棄が終了する任意のストレージ期間のオブジェクトは、完全に構築されたすべてのサブオブジェクト(ユニオンのようなクラスのバリアントメンバーを除く)、つまり、主コンストラクターのサブオブジェクトに対してデストラクタが実行されます(12.6.2)は実行を完了し、デストラクタはまだ実行を開始していません。同様に、オブジェクトの非委任コンストラクターが実行を完了し、そのオブジェクトの委任コンストラクターが例外で終了した場合、オブジェクトのデストラクタが呼び出されます。オブジェクトがnew-expressionで割り当てられた場合、一致する割り当て解除関数(3.7.4.2、5.3.4、12.5)が呼び出され、オブジェクトが占有していたストレージが解放されます。

このプロセス全体は、「スタック巻き戻し」として知られています。

3 tryブロックからthrow式へのパス上に構築された自動オブジェクトのデストラクタを呼び出すプロセスは、「スタック巻き戻し」と呼ばれます。スタックの巻き戻し中に呼び出されたデストラクタが例外を出て終了すると、std :: terminateが呼び出されます(15.5.1)。

スタック巻き戻しは、広く使用されている Resource Acquisition Is Initialization(RAII) と呼ばれる手法の基礎を形成します。

例外がキャッチされない場合、スタックの巻き戻しは必ずしも行われないことに注意してください。この場合、スタックの巻き戻しを行うかどうかは実装次第です。ただし、スタックの巻き戻しが行われたかどうかにかかわらず、この場合は_std::terminate_の最後の呼び出しが保証されます。

C++ 1115.5.1 std :: terminate()関数[except.terminate]

2…一致するハンドラーが見つからない場合、std::terminate()が呼び出される前にスタックが展開されるかどうかは、実装によって定義されます。

57
NPE

はい、デストラクタは、例外のスローによるアンワインドを含め、スタックのアンワインド時に呼び出されることが保証されています。覚えておかなければならない例外を除いて、いくつかのトリックがあります。

  • コンストラクタで例外がスローされた場合、クラスのデストラクタは呼び出されません。
  • 構築初期化リストキャッチブロックでキャッチされると、例外は自動的に再スローされます。
6
user405725

スローがキャッチされた場合、通常はcpp操作が続行されます。これには、デストラクタとスタックポップが含まれます。ただし、例外がキャッチされない場合、スタックのポップは保証されません。

また、ベアスローまたはエンプティスローが私のモバイルコンパイラーでキャッチされません。

例:

#include <Jav/report.h>

int main()
{
 try { throw; }
 catch(...) { rep("I bet this is not caught"); }
 }
1