C++ の例外処理メカニズムがどのように機能するかに興味があります。具体的には、例外オブジェクトはどこに保存され、キャッチされるまで複数のスコープをどのように伝播するのでしょうか? それはいくつかのグローバル領域に保存されていますか?
これはコンパイラ固有のものである可能性があるため、g ++コンパイラスイートのコンテキストで誰かがこれを説明できますか?
C++ の例外処理メカニズムがどのように機能するかに興味があります。具体的には、例外オブジェクトはどこに保存され、キャッチされるまで複数のスコープをどのように伝播するのでしょうか? それはいくつかのグローバル領域に保存されていますか?
これはコンパイラ固有のものである可能性があるため、g ++コンパイラスイートのコンテキストで誰かがこれを説明できますか?
実装は異なる場合がありますが、要件に基づく基本的な考え方がいくつかあります。
例外オブジェクト自体は、ある関数で作成され、その呼び出し元で破棄されるオブジェクトです。したがって、通常、スタック上にオブジェクトを作成することはできません。一方、多くの例外オブジェクトはそれほど大きくありません。したがって、より大きな例外オブジェクトが実際に必要な場合は、たとえば 32 バイトのバッファとヒープへのオーバーフローを作成できます。
実際の支配権の移転に関しては、2 つの戦略が存在します。1 つは、スタックを巻き戻すのに十分な情報をスタック自体に記録することです。これは基本的に、実行するデストラクタと、例外をキャッチする可能性のある例外ハンドラのリストです。例外が発生すると、一致するキャッチが見つかるまで、それらのデストラクタを実行しているスタックを実行します。
2 番目の戦略では、この情報をスタック外のテーブルに移動します。これで、例外が発生したときに、コール スタックを使用して、どのスコープに入ったが、出ていないかを特定できるようになりました。次に、それらは静的テーブルで検索され、スローされた例外が処理される場所と、その間で実行されるデストラクタが決定されます。これは、スタックの例外オーバーヘッドが少ないことを意味します。とにかくリターンアドレスが必要です。テーブルは余分なデータですが、コンパイラはそれらをプログラムのデマンド ロード セグメントに配置できます。
これは、15.1 標準の例外のスローで定義されています。
スローは一時オブジェクトを作成します。
この一時オブジェクトのメモリがどのように割り当てられるかは指定されていません。
一時オブジェクト コントロールの作成後、コール スタック内の最も近いハンドラーに渡されます。スローポイントとキャッチポイントの間のスタックを巻き戻します。スタックが巻き戻されると、スタック変数は作成と逆の順序で破棄されます。
例外が再スローされない限り、一時的なものはキャッチされたハンドラーの最後で破棄されます。
注: 参照によってキャッチする場合、参照は一時オブジェクトを参照します。値によってキャッチする場合、一時オブジェクトは値にコピーされます (したがって、コピー コンストラクターが必要です)。
S.Meyers からのアドバイス (const 参照によるキャッチ)。
try
{
// do stuff
}
catch(MyException const& x)
{
}
catch(std::exception const& x)
{
}
詳細な説明については、こちらをご覧ください。
また、単純な C で使用される基本的な種類の例外処理を実装するためのトリックを調べることも役立つ場合があります。これには、以下の方法で setjmp() と longjmp() を使用する必要があります: 前者は例外ハンドラーをマークするためにスタックを保存し (「catch」のように)、後者は値を「スロー」するために使用されます。「スローされた」値は、呼び出された関数から返されたかのように見えます。「try ブロック」は、setjmp() が再度呼び出されるか、関数が戻ると終了します。
私はこれが古い質問であることを知っていますが、gcc と VC のそれぞれで使用される両方の方法を説明する非常に良い説明があります: http://www.hexblog.com/wp-content/uploads/2012/06/Recon- 2012-Skochinsky-Compiler-Internals.pdf