Каковы признаки инициализации крестов?

Рассмотрим следующий код:

#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?

ИЗМЕНИТЬ:
Я знаю, что я должен использовать скобки, чтобы указать область r, но я хочу знать, почему, например, почему не-POD не может быть определен в операторе переключения нескольких случаев.

Спасибо.

Ответ 1

Версия с 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).

Ответ 2

Вы должны поместить содержимое 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 считается прыжком в этом отношении.

Ответ 4

Я предлагаю вам продвигать свою переменную 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;
    };
}

Одно из преимуществ заключается в том, что компилятор не должен выполнять локальное распределение (a.k.a. нажатие на стек) в каждом блоке case.

Недостатком этого подхода является то, что случаи "падают" в другие случаи (т.е. без использования break), поскольку переменная будет иметь предыдущее значение.

Ответ 5

Если вы определяете переменную в цикле, вы получаете ошибку "пересекает инициализацию". Если вы определяете переменную в первом скрипте кода, все в порядке.