TL; DR
La única forma en que puede declarar una variable con un inicializador o algún objeto no trivial dentro de un caso es introducir un alcance de bloque usando {}
u otra estructura de control que tenga su propio alcance como un bucle o una declaración if .
Detalles sangrientos
Podemos ver que los casos son solo declaraciones etiquetadas como las etiquetas que se usan con una declaración goto ( esto se cubre en la sección 6.1 Declaración etiquetada del borrador del estándar de C ++ ) y podemos ver en el 6.7
párrafo 3 de la sección que saltar una declaración no está permitido en muchos casos , incluidos aquellos con una inicialización:
Es posible transferir a un bloque, pero no de una manera que omita las declaraciones con la inicialización. Un programa que salta 87 desde un punto donde una variable con duración de almacenamiento automático no está dentro del alcance a un punto donde está dentro del alcance está mal formado a menos que la variable tenga un tipo escalar, un tipo de clase con un constructor predeterminado trivial y un destructor trivial, una versión calificada por cv de uno de estos tipos, o una matriz de uno de los tipos anteriores y se declara sin un inicializador (8.5).
y proporciona este ejemplo:
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
}
Tenga en cuenta que aquí hay algunas sutilezas, se le permite saltar más allá de una declaración escalar que no tiene una inicialización, por ejemplo:
switch( n )
{
int x ;
//int x = 10 ;
case 0:
x = 0 ;
break;
case 1:
x = 1 ;
break;
default:
x = 100 ;
break ;
}
es perfectamente válido ( ejemplo vivo ). Por supuesto, si desea declarar la misma variable en cada caso , cada uno necesitará su propio alcance, pero también funciona de la misma manera fuera de las declaraciones de cambio , por lo que no debería ser una gran sorpresa.
En cuanto a la justificación para no permitir el salto después de la inicialización, el informe de defectos 467, aunque cubre un problema ligeramente diferente, proporciona un caso razonable para las variables automáticas :
[...] las variables automáticas, si no se inicializan explícitamente, pueden tener valores indeterminados ("basura"), incluidas las representaciones de trampas, [...]
Probablemente sea más interesante observar el caso en el que extiende un alcance dentro de un interruptor sobre varios casos, los ejemplos más famosos de esto probablemente sean el dispositivo de Duff, que se vería así:
void send( int *to, const int *from, int count)
{
int n = (count + 7) / 8;
switch(count % 8)
{
case 0: do { *to = *from++; // <- Scope start
case 7: *to = *from++;
case 6: *to = *from++;
case 5: *to = *from++;
case 4: *to = *from++;
case 3: *to = *from++;
case 2: *to = *from++;
case 1: *to = *from++;
} while(--n > 0); // <- Scope end
}
}