842 votos

¿Por qué puede ' las variables t declarar en una instrucción switch?

Siempre me he preguntado esto - ¿por qué no pueden declarar variables después de un caso de la etiqueta en una sentencia switch? En C++ se puede declarar variables prácticamente en cualquier parte (y declarando a ellos cerca de su primer uso es, obviamente, una buena cosa), pero el siguiente aún no funcionan:

switch (val)  
{  
case VAL:  
  // This won't work
  int newVal = 42;  
  break;
case ANOTHER_VAL:  
  ...
  break;
}

El de arriba me da el siguiente error (MSC):

la inicialización de 'newVal' es ignorado por el 'caso' de la etiqueta

Esto parece ser una limitación en otros idiomas también. ¿Por qué es esto un problema?

1025voto

Thomas Puntos 6891

El caso de declaraciones son sólo 'etiquetas'. Esto significa que el compilador va a interpretar esto como un salto directamente a la label.The problema aquí es uno de alcance. Las llaves definir el alcance como todo dentro de la " switch " de la declaración. Esto significa que se queda con un ámbito en el que de un salto se realiza más en el código de saltarse la inicialización. La forma correcta de manejar esta es la definición de un ámbito específico a la declaración de caso y definir la variable dentro de ella.

switch (val)
{   
case VAL:  
{
  // This will work
  int newVal = 42;  
  break;
}
case ANOTHER_VAL:  
...
break;
}

130voto

Richard Corden Puntos 12292

Aceptar. Sólo para aclarar esta estrictamente no tiene nada que ver con la declaración. Se refiere sólo a "para saltar sobre las inicialización" (ISO C++ '03 6.7/3)

Muchos de los posts que aquí se han mencionado que saltar por encima de la declaración puede resultar en la variable "no declarado". Esto no es cierto. Una VAINA objeto puede ser declarada sin un inicializador pero tendrá un valor indeterminado. Por ejemplo:

switch (i)
{
   case 0:
     int j; // 'j' has indeterminate value
     j = 0; // 'j' initialized to 0, but this statement
            // is jumped when 'i == 1'
     break;
   case 1:
     ++j;   // 'j' is in scope here - but it has an indeterminate value
     break;
}

Cuando el objeto es un no-POD o agregada el compilador agrega implícitamente un inicializador, y así no es posible saltar por encima de dicha declaración:

class A {
public:
  A ();
};

switch (i)  // Error - jumping over initialization of 'A'
{
   case 0:
     A j;   // Compiler implicitly calls default constructor
     break;
   case 1:
     break;
}

Esta limitación no se limita a la instrucción switch. También es un error usar 'goto' para saltar por encima de una inicialización:

goto LABEL;    // Error jumping over initialization
int j = 0; 
LABEL:
  ;

Un poco de trivia es que esta es una diferencia entre C++ y C. En C, no es un error para saltar por encima de la inicialización.

Como otros han mencionado, la solución es añadir un bloque anidado para que la vida útil de la variable se limita al caso individual de la etiqueta.

35voto

Mark Ingram Puntos 24995

La sentencia switch todo es en el mismo ámbito, para conseguir alrededor de él, haga esto:

switch (val)  
{  
case VAL:  
{
  // This **will** work
  int newVal = 42;  
}
  break;
case ANOTHER_VAL:  
  ...
  break;
}

Nota los soportes

20voto

emk Puntos 27772

Usted no puede hacer esto, porque case etiquetas en realidad son sólo puntos de entrada en el bloque que contiene.

Esto es más claramente ilustrado por Duff del dispositivo. Aquí está el código de la Wikipedia:

strcpy(char *to, char *from, size_t count) {
    int n = (count + 7) / 8;
    switch (count % 8) {
    case 0: do { *to = *from++;
    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);
    }
}

Observe cómo la case etiquetas ignorar totalmente el bloque de límites. Sí, este es el mal. Pero esta es la razón por la que su ejemplo de código no funciona. Saltar a case etiqueta es el mismo como el uso de goto, por lo que no se les permite saltar por encima de una variable local con un constructor.

Como varios otros carteles han indicado, se necesita poner en un bloque de tu propio:

switch (...) {
    case FOO: {
        MyObject x(...);
        ...
        break; 
    }
    ...
 }

16voto

MrZebra Puntos 6508

La mayoría de las respuestas hasta ahora está equivocada en un aspecto: puede declarar variables después de la instrucción del caso, pero no se puede inicializarlos:

case 1:
    int x; // Works
    int y = 0; // Error, initialization is skipped by case
    break;
case 2:
    ...

Como se mencionó anteriormente, una buena manera de evitarlo es usar frenillos para crear un ámbito para su caso.

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X