交叉初始化的标志是什么?

考虑以下代码:

#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 语句中定义 non-POD。

98191 次浏览

You should put the contents of the case in brackets to give it scope, that way you can declare local variables inside it:

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

The version with int r = x + y; won't compile either.

The problem is that it is possible for r to come to scope without its initializer being executed. The code would compile fine if you removed the initializer completely (i.e. the line would read int r;).

The best thing you can do is to limit the scope of the variable. That way you'll satisfy both the compiler and the reader.

switch(i)
{
case 1:
{
int r = 1;
cout << r;
}
break;
case 2:
{
int r = x - y;
cout << r;
}
break;
};

The Standard says (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).

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 and is declared without an initializer.

[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]

The transfer from the condition of a switch statement to a case label is considered a jump in this respect.

I suggest you promote your r variable before the switch statement. If you want to use a variable across the case blocks, (or the same variable name but different usages), define it before the switch statement:

#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;
};
}

One of the benefits is that the compiler does not have to perform local allocation (a.k.a. pushing onto the stack) in each case block.

A drawback to this approach is when cases "fall" into other cases (i.e. without using break), as the variable will have a previous value.