交叉初始化的迹象是什么?


84

考虑以下代码:

#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

我知道我应该使用方括号来指定的范围r,但是我想知道为什么,例如,为什么不能在多案例switch语句中定义非POD。


1
根据下面的答案,我对第3点的理解是,此错误是对c ++的过度限制。如果在标签后未使用r,则不会产生影响(即使此处的示例使用r,在情况2中也可以将其删除,并且编译器会给出相同的错误)。更好的证明是C,甚至C11中都允许。
calandoa

Answers:


95

的版本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),否则程序将从具有自动存储持续时间的局部变量不在范围内的点跳转到其处于范围内的点的格式错误。


但是我的G ++确实允许int r = x + y
超2010年

10
好吧,我的g ++没有。再次检查或升级编译器。
avakar 2010年

谢谢,这对我很有帮助。我认为C编译器甚至不允许某些代码之后进行声明。显然,C99允许虽然... stackoverflow.com/questions/7859424/...
M-RIC

36

您应该将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标签的转移在这方面被认为是跳跃。


1
欢迎使用堆栈溢出。您应该提供引文来源,这是C ++ 03:6.7 / 3。也恰好是我在回答中引用的同一段。
阿瓦卡

0

我建议您rswitch声明前提升变量。如果要跨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)时,因为变量将具有先前的值。


2
我建议反过来做。在任何一种情况下,编译器都不必执行“本地分配”(实际上,不需要)。
avakar 2010年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.