web-dev-qa-db-ja.com

十字架の初期化の兆候は何ですか?

次のコードを検討してください。

#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の問題は何ですか?

[〜#〜] edit [〜#〜]
ブラケットを使用してrのスコープを指定する必要があることは知っていますが、理由、たとえば、非PODを複数ケースのswitchステートメントで定義できなかった理由を知りたいです。

ありがとう。

80
Jichao

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)なしで宣言されていない限り、不正な形式です。

93
avakar

caseの内容を角かっこで囲んでスコープを指定する必要があります。その方法で、その中にローカル変数を宣言できます。

switch(i) {
    case 1:
        {
            // int r = x + y; -- OK
            int r = 1; // Failed to Compile
            cout << r;
        }
        break;
    case 2:
        ...
        break;
};
35
Péter Török

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

3
Ashish Yadav

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を使用しない場合)です。

0
Thomas Matthews