17

ここで、ふと疑問に思ったことがあります。次のコードが与えられた場合、その出力について確信を持てますか?

void f() {
  int i = 0; 
  z: if(i == 1) goto x; else goto u; 
  int a; 
  x: if(a == 10) goto y; 
  u: a = 10; i = 1; goto z; 
  y: std::cout << "finished: " << a; 
}

finished: 10これは、C++ 標準に従って出力されることが保証されていますか? aまたは、コンパイラは、格納されgotoているレジスタを占有できaますか?

4

4 に答える 4

6

注:最初にこれに対するコメントを読んでください。Johannes は、適切に配置された 1 つの標準的な引用で、多かれ少なかれ私の議論全体を否定しました。;-)


私は C++ 標準を利用できないので、C 標準から推定する必要があります。

(私にとっては)驚くべきことに、章 6.2.1識別子のスコープでは、宣言の時点から始まる識別子のスコープについて何も述べていません (私が推測したように)。int a、あなたの例では、「関連するブロックの最後で終了する」block scopeがあり、それについて言われていることはそれだけです。章6.8.6.1 gotoステートメントは、「gotoステートメントは、可変的に変更された型を持つ識別子のスコープ外からその識別子のスコープ内にジャンプしてはならない」と述べていますが、ブロック内でgotoのみジャンプするため(および、したがって、 の範囲は、ISO/IEC 9899:1999 に関する限り問題ないようですint a

これにはかなり驚かされます…

編集 #1:後で簡単に Google を検索して、C++0x の最終ドラフトを手に入れました。関連する声明は、ここにあると思います(6.7宣言声明、私の強調表示):

ブロックに転送することは可能ですが、初期化で宣言をバイパスする方法ではできません。自動保存期間を持つ変数がスコープ内にないポイントからスコープ内にあるポイントにジャンプするプログラムは、変数がスカラー型、単純なデフォルト コンストラクターと単純なデストラクタを持つクラス型を持たない限り、形式が正しくありません。これらの型のいずれかの cv 修飾バージョン、または上記の型のいずれかの配列であり、 initializer なしで宣言されています

あなたのコードは標準の基準で問題ないと思います。しかし、お尻は醜いです、気をつけてください。;-)

編集#2:int a後方へのジャンプによる破壊の可能性についてのコメントを読んで、これを見つけました(6.6ジャンプステートメント、私の強調表示):

ループからの転送、ブロックからの転送、または自動保存期間を持つ初期化された変数を超える転送には、転送元のポイントではスコープ内にあるが転送先のポイントではスコープ内にない、自動ストレージ期間を持つオブジェクト の破棄が含まれます。

1つint aは「初期化」されておらず、標準用語を正しく理解していればオブジェクトではありません。

于 2011-07-22T14:22:22.380 に答える
5

6.7/3 はそれを言う

自動保存期間を持つローカル変数がスコープ内にないポイントからスコープ内にあるポイントにジャンプするプログラムは、変数が POD 型 (3.9) を持ち、初期化子 (8.5) なしで宣言されていない限り、整形されません。

それで大丈夫なはずです。

次に、6.6/2 で:

スコープから出ると (どのように達成されても)、デストラクタ (12.4) は、そのスコープで宣言された自動保存期間 (3.7.2) (名前付きオブジェクトまたは一時オブジェクト) を持つすべての構築済みオブジェクトに対して、宣言の逆の順序で呼び出されます。

これaは、ジャンプして戻ったときに乾杯することを意味しz、の初期化子なし宣言がa2回目の実行時にどのように動作するかについて保証することはできません。

6.7/2 を参照:

自動保存期間 (3.7.2) を持つ変数は、それらの宣言ステートメントが実行されるたびに初期化されます。ブロックで宣言された自動保存期間を持つ変数は、ブロックの終了時に破棄されます (6.6)。

したがって、10 が得られるという保証はないように思えますが、そうならないコンパイラーを想像するのは難しいようです。

于 2011-07-22T14:31:01.537 に答える
0

finished: 10C ++標準に従って出力することが保証されていますか?

はい、そうだと思います。

なんで ?宣言からaスコープの終わり(関数の終わり)まで存続し、定義上、初期化できるのは1回だけであり、それ以降は、関数の終わりにある破棄までその値を保持します。

于 2011-07-22T18:52:35.397 に答える
0

変数の定義を省略することはできません。エラーになるはずです。

于 2011-07-22T14:08:28.733 に答える