考虑以下代码:
#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++抱怨:
<source>: In function 'int main()': <source>:14:14: error: jump to case label 14 | case 2: | ^ <source>:11:17: note: crosses initialization of 'int r' 11 | int r = 1; // Failed to Compile | ^
我的问题是:
crosses initialization
?x + y
编译通过,而后者编译失败?crosses initialization
有哪些问题?我知道我应该使用括号来指定
r
的范围,但我想知道为什么,例如为什么不能在多情况switch语句中定义非POD。
带有
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
),因为变量将具有先前的值。