警告:この回答はC ++にのみ該当します。規則はCではかなり異なります。
ではないだろうx
漏洩しますか?
いいえ、絶対にありません。
これは、goto
C ++の組み込みスコープメカニズムをオーバーライドできるようにする低レベルの構造であるという神話です。(どちらかと言えば、longjmp
この傾向がある可能性があります。)
ラベル(ラベルを含むcase
)を使用して「悪いこと」を実行できないようにする次のメカニズムを検討してください。
1.ラベルのスコープ
関数間をジャンプすることはできません。
void f() {
int x = 0;
goto lol;
}
int main() {
f();
lol:
return 0;
}
// error: label 'lol' used but not defined
[n3290: 6.1/1]:
[..]ラベルのスコープは、ラベルが表示される機能です。[..]
2.オブジェクトの初期化
オブジェクトの初期化を飛び越えることはできません。
int main() {
goto lol;
int x = 0;
lol:
return 0;
}
// error: jump to label ‘lol’
// error: from here
// error: crosses initialization of ‘int x’
あなたがジャンプする場合は、バックオブジェクトの初期化を越え、その後、オブジェクトの前の「インスタンス」が破壊されました。
struct T {
T() { cout << "*T"; }
~T() { cout << "~T"; }
};
int main() {
int x = 0;
lol:
T t;
if (x++ < 5)
goto lol;
}
// Output: *T~T*T~T*T~T*T~T*T~T*T~T
[n3290: 6.6/2]:
[..]ループ外、ブロック外、または自動ストレージ期間のある初期化された変数を越えて転送すると、転送元のポイントではスコープ内にあるが、転送先のポイントではない、自動ストレージ期間のあるオブジェクトが破棄されます。 。[..]
明示的に初期化されていなくても、オブジェクトのスコープにジャンプすることはできません。
int main() {
goto lol;
{
std::string x;
lol:
x = "";
}
}
// error: jump to label ‘lol’
// error: from here
// error: crosses initialization of ‘std::string x’
... 「複雑な」構造を必要としないため、言語が関係なく処理できる特定の種類のオブジェクトを除く:
int main() {
goto lol;
{
int x;
lol:
x = 0;
}
}
// OK
[n3290: 6.7/3]:
ブロックに転送することは可能ですが、初期化で宣言をバイパスする方法ではできません。自動ストレージ期間を持つ変数がスコープ内にないポイントからスコープ内にあるポイントにジャンプするプログラムは、変数がスカラー型、自明なデフォルトコンストラクターおよび自明なデストラクタを持つクラス型でない限り、形式が正しくありません。これらのタイプのいずれかのcv修飾バージョン、または前述のタイプのいずれかの配列であり、初期化子なしで宣言されています。[..]
3.ジャンプは他のオブジェクトのスコープに従います
同様に、自動記憶域期間を持つオブジェクトはありませんが、「漏れた」ときにgoto
出て、その範囲の:
struct T {
T() { cout << "*T"; }
~T() { cout << "~T"; }
};
int main() {
{
T t;
goto lol;
}
lol:
return 0;
}
// *T~T
[n3290: 6.6/2]:
スコープからの出口で(達成された場合)、そのスコープで作成された自動ストレージ期間(3.7.3)のオブジェクトは、作成とは逆の順序で破棄されます。[..]
結論
上記のメカニズムによりgoto
、言語を壊すことがなくなります。
もちろん、これは自動的にあなたが使用「すべき」という意味ではありませんgoto
任意の与えられた問題のために、それはありません、それはほとんどの人が信じて、共通の神話リードとして「悪」としてではないことを意味します。