6

goto を使用して try ブロックを終了し、catch ブロックを完全に回避するのが好きな非常に賢い人から継承したコードがいくつかあります。

それは間違いなく機能し、これは合法であると思います(C++標準では、スコープから出るとすべてが適切にクリーンアップされると書かれていると思います。これは、私のプラットフォームに例外を実装するためにコンパイラがしなければならなかったことすべてに当てはまると思います) .

これは本当に合法ですか?これは私が書くようなものではありませんが (半分巧妙すぎます)、明らかに機能しており、なぜこれが問題ないのかを理解したいだけです。

4

4 に答える 4

11

それは合法である可能性があり、コードが何をするかによって異なります。たとえば、catch ブロックから飛び出すコードを作成し、それを言語のランタイム ライブラリで使用しています (簡単にするために、ランタイム ライブラリを使用するコードは itanium 例外処理を実装していませんが、longjmp/setjmp を使用して実装しています)。ただし、ランタイム ライブラリは、C++ の例外を通じて、それを使用しますそして、それらの間で制御をきれいに移すメカニズムが必要です。

try {
  doSomethingThatMayFail();
} catch(DiagnosticException&) {
  goto unwind;
}

if(0) {
unwind:
  longjmp(&lastSafePoint, 0);
}

これをマクロに入れて、非常に書きやすいようにします。here は、診断例外のgoto例外処理中に割り当てられたリソースをクリーンアップするために必要です。

いつものように、「この機能を使用しないでください」とは言わないでください。代わりに、すべての使用について慎重に検討する必要があります。

于 2012-07-12T19:12:16.380 に答える
10

標準 はい、それは合法であり、明確に定義されています:

C++2003: 6.6 ジャンプ ステートメント

スコープから出ると (どのように達成されても)、デストラクタ (12.4) は、そのスコープで宣言された自動保存期間 (3.7.2) (名前付きオブジェクトまたは一時オブジェクト) を持つすべての構築済みオブジェクトに対して、宣言の逆の順序で呼び出されます。ループからの転送、ブロックからの転送、または自動ストレージ期間を持つ初期化された変数の過去への転送には、転送元のポイントではスコープ内にあるが転送先のポイントではスコープ内にない、自動ストレージ期間を持つ変数の破棄が含まれます。(ブロックへの転送については 6.7 を参照)。[注: ただし、プログラムは、自動保存期間を持つクラス オブジェクトを破棄することなく (たとえば、exit() または abort()(18.3) を呼び出すことによって) 終了できます。]

gotoそもそも使用することの宗教的意味についてコメントしないことを選択します.

于 2012-07-12T19:08:21.703 に答える
7

ジャンプステートメントに関する C++03 標準のセクションよりもさらに具体的には、「例外処理」節 (15/2) の try ブロックについて次のように述べています。

goto、break、return、または continue ステートメントを使用して、try ブロックまたはハンドラーから制御を移すことができます。これが発生すると、try ブロックで宣言された各変数は、その宣言を直接含むコンテキストで破棄されます。

C++11 には同じ文言が含まれています。

ただし、(または)を使用して try ブロックにジャンプすることはできません。gotoswitch

goto または switch ステートメントを使用して、制御を try ブロックまたはハンドラーに移してはなりません。

于 2012-07-12T19:12:35.490 に答える
2

それは合法です。悪いコードです。やらないでください。使用しないでくださいgoto

于 2012-07-12T19:07:13.653 に答える