vectores que programacion llenar funciones estructuras ejemplos como arreglo c++ switch-statement

c++ - que - Usando{} en una declaración de caso. ¿Por qué?



que es un arreglo en c++ (6)

El uso de corchetes en el interruptor denota un nuevo bloque de alcance según lo dicho por Rotem.

Pero puede ser también para mayor claridad cuando lees. Para saber dónde se detiene el caso, ya que es posible que tenga una pausa condicionada.

¿De qué sirve usar { y } en una declaración de case ? Normalmente, no importa cuántas líneas haya en una declaración de case , todas las líneas se ejecutan. ¿Es solo una regla con respecto a los compiladores antiguos / nuevos o hay algo detrás de eso?

int a = 0; switch (a) { case 0:{ std::cout << "line1/n"; std::cout << "line2/n"; break; } }

y

int a = 0; switch (a) { case 0: std::cout << "line1/n"; std::cout << "line2/n"; break; }


Es un hábito que le permite inyectar declaraciones de variables con el destructor resultante (o conflictos de alcance) en cláusulas de case . Otra forma de verlo es que están escribiendo para el idioma que desearían tener, donde todo el control de flujo consiste en bloques y no en secuencias de enunciados.


Las razones pueden ser:

  1. Legibilidad, mejora visualmente cada caso como una sección de ámbito.
  2. Declarando las diferentes variables con el mismo nombre para varios casos de cambio.
  3. Micro optimizaciones: posibilidad de una variable asignada a los recursos realmente costosa que desee destruir tan pronto como salga del alcance del caso, o incluso un escenario más espagueti del uso del comando "GOTO".

Verifique esto como una restricción básica del compilador y comenzará a preguntarse qué está sucediendo:

int c; c=1; switch(c) { case 1: //{ int *i = new int; *i =1; cout<<*i; break; //} default : cout<<"def"; }

Esto te dará un error:

error: jump to case label [-fpermissive] error: crosses initialization of ‘int* i’

Mientras que este no:

int c; c=1; switch(c) { case 1: { int *i = new int; *i =1; cout<<*i; break; } default : cout<<"def"; }


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 instrucción if .

Detalles de Gory

Podemos ver que los casos son solo declaraciones etiquetadas como las etiquetas usadas con una declaración goto ( esto está cubierto en el borrador de la norma C ++ 6.1 Declaración etiquetada ) y podemos ver en la sección 6.7 párrafo 3 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 puentee las declaraciones con la inicialización. Un programa que salta 87 desde un punto donde una variable con duración de almacenamiento automática no está en alcance hasta un punto en el que está dentro del alcance está mal formado a menos que la variable tenga tipo escalar, tipo de clase con un constructor trivial predeterminado y un destructor trivial. una versión cv-calificada 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 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 en vivo ). Por supuesto, si desea declarar la misma variable en cada caso , cada uno necesitará su propio alcance, pero funciona de la misma manera fuera de las declaraciones de cambio también, 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 ver el caso en el que extiendes un alcance dentro de un interruptor en múltiples casos, los ejemplos más famosos de esto es probablemente 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 } }


{} Denota un nuevo bloque de alcance .

Considere el siguiente ejemplo muy artificial:

switch (a) { case 42: int x = GetSomeValue(); return a * x; case 1337: int x = GetSomeOtherValue(); //ERROR return a * x; }

Obtendrá un error de compilación porque x ya está definido en el alcance.

La separación de estos en su propio sub-ámbito eliminará la necesidad de declarar x fuera de la declaración de cambio.

switch (a) { case 42: { int x = GetSomeValue(); return a * x; } case 1337: { int x = GetSomeOtherValue(); //OK return a * x; } }