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


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

#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 но я хочу знать, почему, например, почему non-POD не может быть определено в операторе переключателя мульти-случая.

спасибо.

4 75

4 ответа:

версия 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;
    };
}

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

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