Каковы признаки инициализации крестов?
Рассмотрим следующий код:
#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
Если вы определяете переменную в цикле, вы получаете ошибку "пересекает инициализацию". Если вы определяете переменную в первом скрипте кода, все в порядке.