goto
がデストラクタなどを呼び出さずにコードのビットをジャンプするのは本当ですか?
例えば.
void f() {
int x = 0;
goto lol;
}
int main() {
f();
lol:
return 0;
}
x
はリークされませんか?
警告:この回答はC++に関係しますのみ;規則はCではかなり異なります。
x
はリークされませんか?
いいえ、絶対にありません
goto
は、C++の組み込みスコープメカニズムをオーバーライドできるようにする低レベルの構成要素であるというのは神話です。 (どちらかと言えば、これが起こりやすいのはlongjmp
です。)
ラベル(case
ラベルを含む)を使用して「悪いこと」を実行できないようにする次のメカニズムを検討してください。
関数間をジャンプすることはできません。
void f() {
int x = 0;
goto lol;
}
int main() {
f();
lol:
return 0;
}
// error: label 'lol' used but not defined
[n3290: 6.1/1]:
[..]ラベルのスコープは、ラベルが表示される関数です。 [..]
オブジェクトの初期化を飛び越えることはできません。
int main() {
goto lol;
int x = 0;
lol:
return 0;
}
// error: jump to label ‘lol’
// error: from here
// error: crosses initialization of ‘int x’
オブジェクトの初期化をまたいでbackジャンプすると、 オブジェクトの以前の「インスタンス」は破棄されます :
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修飾バージョン、または前述のタイプのいずれかの配列であり、初期化子なしで宣言されています。 [..]
同様に、自動ストレージ期間を持つオブジェクト arenot「リーク」されたときに、スコープ外に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
を使用する必要があることを自動的に意味するわけではありませんが、doesは、それが「悪」に近いわけではないことを意味します「一般的な神話が人々を信じさせるように。