次のコードを検討してください。
#include <iostream>
using namespace std;
int main()
{
int x, y, i;
cin >> x >> y >> i;
switch(i) {
case 1:
// int r = x + y; -- OK
int r = 1; // Failed to Compile
cout << r;
break;
case 2:
r = x - y;
cout << r;
break;
};
}
G ++はcrosses initialization of 'int r'
に文句を言います。私の質問は:
crosses initialization
とは何ですか?x + y
がコンパイルをパスするのに、後で失敗するのはなぜですか?crosses initialization
の問題は何ですか?[〜#〜] edit [〜#〜]:
ブラケットを使用してr
のスコープを指定する必要があることは知っていますが、理由、たとえば、非PODを複数ケースのswitchステートメントで定義できなかった理由を知りたいです。
ありがとう。
int r = x + y;
を含むバージョンもコンパイルされません。
問題は、r
が初期化子を実行せずにスコープに入る可能性があることです。初期化子を完全に削除すると、コードは正常にコンパイルされます(つまり、行はint r;
になります)。
最善の方法は、変数のスコープを制限することです。そうすれば、コンパイラと読者の両方を満足させることができます。
switch(i)
{
case 1:
{
int r = 1;
cout << r;
}
break;
case 2:
{
int r = x - y;
cout << r;
}
break;
};
標準では(6.7/3)と書かれています:
ブロックに転送することは可能ですが、初期化で宣言をバイパスすることはできません。自動保存期間を持つローカル変数がスコープ内にないポイントからスコープ内にあるポイントにジャンプするプログラムは、変数がPODタイプ(3.9)で初期化子(8.5)なしで宣言されていない限り、不正な形式です。
case
の内容を角かっこで囲んでスコープを指定する必要があります。その方法で、その中にローカル変数を宣言できます。
switch(i) {
case 1:
{
// int r = x + y; -- OK
int r = 1; // Failed to Compile
cout << r;
}
break;
case 2:
...
break;
};
ブロックに転送することは可能ですが、初期化で宣言をバイパスすることはできません。自動保存期間を持つローカル変数がスコープ内にないポイントからスコープ内にあるポイントにジャンプするプログラムは、変数がPOD型を持ち、初期化子なしで宣言されていない限り、不正な形式です。
[Example: Code:
void f()
{
// ...
goto lx; // ill-formed: jump into scope of `a'
// ...
ly:
X a = 1;
// ...
lx:
goto ly; // ok, jump implies destructor
// call for `a' followed by construction
// again immediately following label ly
}
--end example]
Switchステートメントの条件からcaseラベルへの転送は、この点でジャンプと見なされます。
r
ステートメントの前にswitch
変数を昇格することをお勧めします。 case
ブロック全体で変数を使用する場合(または同じ変数名で異なる使用法)、switchステートメントの前に定義します。
#include <iostream>
using namespace std;
int main()
{
int x, y, i;
cin >> x >> y >> i;
// Define the variable before the switch.
int r;
switch(i) {
case 1:
r = x + y
cout << r;
break;
case 2:
r = x - y;
cout << r;
break;
};
}
利点の1つは、各case
ブロックで、コンパイラーがローカル割り当て(a.k.a。スタックへのプッシュ)を実行する必要がないことです。
このアプローチの欠点は、変数が以前の値を持つため、ケースが他のケースに「陥る」場合(つまり、break
を使用しない場合)です。