【问题标题】:What are the signs of crosses initialization?十字架初始化的迹象是什么?
【发布时间】:2010-03-06 13:53:39
【问题描述】:

考虑以下代码:

#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。

【问题讨论】:

  • 我的理解,给出下面的答案,第 3 点是这个错误是对 c++ 的过度限制。如果标签后面没有使用r,则没有影响(即使这里的示例使用了r,也可以在情况2中将其删除,编译器会给出相同的错误)。更好的证据是它在 C 中是允许的,甚至在 C11 中也是如此。
  • Error: Jump to case label的可能重复

标签: c++ initialization


【解决方案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) 的情况下声明。

【讨论】:

  • 但我的 G++ 确实允许 int r = x + y
  • 好吧,我的 g++ 没有。再次检查或升级编译器。
  • 谢谢,这对我很有帮助。我认为 C 编译器甚至不允许声明出现在 一些代码之后。显然 C99 允许这样做...stackoverflow.com/questions/7859424/…
【解决方案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 标签的转移在这方面被认为是一个跳转。

    【讨论】:

    • 欢迎来到 Stack Overflow。你应该为你的引文提供来源,这是 C++03:6.7/3。它也恰好是我在回答中引用的同一段。
    【解决方案4】:

    我建议您在 switch 语句之前提升您的 r 变量。如果要跨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),因为变量将具有先前的值。

    【讨论】:

    • 我建议反其道而行之。在任何一种情况下,编译器都不必执行“本地分配”(实际上它不会)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-28
    相关资源
    最近更新 更多