2010-03-06 3 views
69

Рассмотрим следующий код:Каковы признаки инициализации крестов?

#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' .my вопросы:

  1. Что такое crosses initialization?
  2. Почему первый инициализатор x + y передает компиляцию, но позже не удалось?
  3. В чем проблема так называемого crosses initialization?

EDIT:
Я знаю, что я должен использовать скобки, чтобы указать область r, но я хочу знать, почему, например, почему не-POD не может быть определена в нескольких сазе переключателя.

Спасибо.

+1

Мое понимание, учитывая приведенные ниже ответы, для пункта 3 состоит в том, что эта ошибка является чрезмерным ограничением C++. Если r не используется после метки, нет никакого влияния (даже если в примере здесь используется r, его можно удалить в случае 2, и компилятор даст ту же ошибку). Лучшее доказательство состоит в том, что оно разрешено в C и даже в C11. – calandoa

+0

Возможный дубликат [Error: Jump to case label] (http://stackoverflow.com/questions/5685471/error-jump-to-case-label) –

ответ

81

версия с 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):

It is possible to transfer into a block, but not in a way that bypasses declarations with initialization. A program that jumps from a point where a local variable with automatic storage duration is not in scope to a point where it is in scope is ill-formed unless the variable has POD type (3.9) and is declared without an initializer (8.5).

+0

Но мой G ++ разрешает 'int r = x + y'. – Jichao

+9

Ну, у меня g ++ нет. Еще раз проверьте или обновите компилятор. – avakar

+0

спасибо, это было полезно для меня. Я думаю, что компилятор C даже не позволяет объявлению появляться _after_ некоторого кода. По-видимому, C99 позволяет это, хотя ... http://stackoverflow.com/questions/7859424/why-was-mixing-declarations-and-code-forbidden-up-until-c99 –

31

Вы должны поместить содержимое case в скобках, чтобы дать ему объем, таким образом, вы можете объявить локальные переменные внутри него:

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

можно передавать в блок, но не таким способом, который обходит декларации с инициализацией. Программа, которая перескакивает с точки, где локальная переменная с продолжительностью автоматического хранения не находится в области до точки, где она находится в области, плохо сформирована, если только переменная не имеет тип 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] 

Передача из условия оператора переключения на метку корпуса считается скачком в этом отношении.

+1

Добро пожаловать в Stack Overflow. Вы должны предоставить источники для своих цитат, это C++ 03: 6.7/3. Это также тот же самый пункт, который я привел в моем ответе. – avakar

0

Я предлагаю вам продвигать свою переменную r перед заявлением switch. Если вы хотите использовать переменную поперек case блоков, (или же имя переменной, но разные порядки), определить его перед оператором коммутатора:

#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), так как переменная будет иметь предыдущее значение.

+2

Я бы предложил сделать это наоборот. Компилятор не должен выполнять «локальное распределение» в любом случае (и на практике он не будет). – avakar

Смежные вопросы