クロスの初期化の兆候は何ですか?


84

次のコードについて考えてみます。

#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'ます。私の質問は次のとおりです。

  1. crosses initializationですか?
  2. 最初の初期化子x + yがコンパイルに合格したのに、後者が失敗したのはなぜですか?
  3. いわゆるの問題は何crosses initializationですか?

のスコープを指定するために角かっこを使用する必要があることはわかっていますが、rたとえば、非PODをマルチケースswitchステートメントで定義できなかった理由を知りたいです。


1
以下の答えを考えると、ポイント3についての私の理解は、このエラーはc ++の過度の制限であるということです。ラベルの後にrが使用されていない場合、影響はありません(ここでの例でrを使用している場合でも、ケース2で削除でき、コンパイラーは同じエラーを出します)。より良い証拠は、Cで、さらにはC11でも許可されていることです。
calandoa 2013年

回答:


95

のバージョン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)、形式が正しくありません。


しかし、私のG ++では許可されていますint r = x + y
Jichao 2010年

10
まあ、私のg ++​​はそうではありません。再度確認するか、コンパイラをアップグレードしてください。
avakar 2010年

おかげで、それは私に役立ちました。Cコンパイラでは、コードの後に宣言を付けることすらできないと思います。どうやらC99は、しかし...ことができますstackoverflow.com/questions/7859424/...
M-RIC

36

caseスコープを指定するには、中括弧の内容を括弧で囲む必要があります。そうすれば、その中にローカル変数を宣言できます。

switch(i) {
    case 1:
        {
            // int r = x + y; -- OK
            int r = 1; // Failed to Compile
            cout << r;
        }
        break;
    case 2:
        ...
        break;
};

3

ブロックに転送することは可能ですが、初期化で宣言をバイパスする方法ではできません。自動ストレージ期間のローカル変数がスコープ内にないポイントからスコープ内にあるポイントにジャンプするプログラムは、変数が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ラベルへの転送は、この点でジャンプと見なされます。


1
StackOverflowへようこそ。引用のソースを提供する必要があります。これはC ++ 03:6.7 / 3です。それはまた、私が私の答えで引用したのと同じ段落です。
avakar 2010年

0

ステートメントのr前に変数を宣伝することをお勧めしますswitchcaseブロック間で変数を使用する場合(または同じ変数名で使用法が異なる場合)、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です。

このアプローチの欠点はbreak、変数が以前の値を持つため、ケースが他のケースに「分類」される場合(つまり、を使用しない場合)です。


2
逆にすることをお勧めします。どちらの場合も、コンパイラは「ローカル割り当て」を実行する必要はありません(実際には実行されません)。
avakar 2010年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.