¿Las declaraciones de cambio siempre deben contener una cláusula predeterminada?

255

En una de mis primeras revisiones de código (hace un tiempo), me dijeron que es una buena práctica incluir una cláusula predeterminada en todas las declaraciones de cambio. Recientemente recordé este consejo, pero no recuerdo cuál era la justificación. Me suena bastante extraño ahora.

  1. ¿Hay alguna razón sensata para incluir siempre una declaración predeterminada?

  2. ¿Es este idioma dependiente? No recuerdo qué idioma estaba usando en ese momento, ¿tal vez esto se aplica a algunos idiomas y no a otros?

tttppp
fuente
99
Dependerá en

Respuestas:

277

Los casos de cambio casi siempre deberían tener un defaultcaso.

Razones para usar un default

1.Para 'atrapar' un valor inesperado

switch(type)
{
    case 1:
        //something
    case 2:
        //something else
    default:
        // unknown type! based on the language,
        // there should probably be some error-handling
        // here, maybe an exception
}

2. Para manejar acciones 'predeterminadas', donde los casos son de comportamiento especial.

Usted ve MUCHO en los programas controlados por menús y los scripts de shell bash. También puede ver esto cuando una variable se declara fuera del caso de cambio pero no se inicializa, y cada caso la inicializa en algo diferente. Aquí, el valor predeterminado también debe inicializarse para que el código de línea que accede a la variable no genere un error.

3. Para mostrarle a alguien que lee su código que ha cubierto ese caso.

variable = (variable == "value") ? 1 : 2;
switch(variable)
{
    case 1:
        // something
    case 2:
        // something else
    default:
        // will NOT execute because of the line preceding the switch.
}

Este fue un ejemplo demasiado simplificado, pero el punto es que alguien que lea el código no debería preguntarse por qué variableno puede ser otra cosa que 1 o 2.


El único caso que se me ocurre que NO debo usar defaultes cuando el interruptor está verificando algo donde es bastante obvio que cualquier otra alternativa puede ignorarse felizmente

switch(keystroke)
{
    case 'w':
        // move up
    case 'a':
        // move left
    case 's':
        // move down
    case 'd':
        // move right
    // no default really required here
}
Vanwaril
fuente
26
Su ejemplo con respecto a las pulsaciones de teclas contradice el resto de lo que acaba de decir. : | Creo que un poco más de explicación tendría sentido, como por ejemplo: no le importa un valor predeterminado en este caso porque si se presiona otra tecla, no le importa, pero si se pasa una variable es diferente de lo esperado, nos importa .
Andrew
1
Al mismo tiempo, si está verificando un parámetro GET, es posible que no desee que se genere una excepción cada vez que un usuario cambia la URL de obtención a algo que no es válido: [
Andrew
44
@ Andrew WASD es común para los movimientos de personajes de juegos de computadora. No necesitaría ninguna acción predeterminada, ya que se podrían asignar otras teclas a otras interacciones. En este tipo de cambio, es bueno llamar a funciones de movimiento.
jemiloii
13
Algunos compiladores advierten al activar una enumeración si se pierde un caso, y agregar un caso predeterminado suprimirá esa advertencia. Dado que esta es, en mi experiencia, una fuente de error muy común (olvidando actualizar un interruptor en algún lugar después de agregar un valor de enumeración), esta parece ser una muy buena razón para omitir un caso predeterminado.
rdb
3
@virusrocks Si su condición es una enumeración, aún puede tener valores inesperados. Por ejemplo, si agrega un nuevo valor a la enumeración y olvida actualizar un modificador. Además, en algunos idiomas puede asignar valores enteros a las enumeraciones. En C ++ enum MyEnum { FOO = 0, BAR = 1 }; MyEnum value = (MyEnum)2;hace una MyEnuminstancia válida que no es igual a FOOo BAR. Si cualquiera de estos problemas causara un error en su proyecto, un caso predeterminado lo ayudará a encontrar el error muy rápidamente, ¡a menudo sin necesidad de depurador!
cdgraham
54

No.

¿Qué pasa si no hay una acción predeterminada? El contexto importa. ¿Qué pasa si solo te importa actuar con unos pocos valores?

Tome el ejemplo de leer las pulsaciones de teclas para un juego

switch(a)
{
   case 'w':
     // Move Up
     break;
   case 's':
     // Move Down
     break;
   case 'a':
     // Move Left
     break;
   case 'd':
     // Move Right
     break;
}

Agregando:

default: // Do nothing

Es solo una pérdida de tiempo y aumenta la complejidad del código sin ningún motivo.

Jared Kells
fuente
14
Buen ejemplo. Pero, de hecho, al agregar una cláusula predeterminada con un // do nothingcomentario simple, queda claro que está 'bien' si no se cubren todos los casos, a diferencia de otras declaraciones de cambio donde esto sería 'no está bien'.
The Nail
8
No. La codificación no se trata solo de manejar algunos casos. También sirve como documento. Al escribir default: y comentar como // No hacer nada ni otra cosa, la legibilidad del código se vuelve mejor.
JongAm Park
22
No estoy de acuerdo con los otros comentarios. Agregar por defecto // No hacer nada agrega muy poco a menos que no sepa cómo funciona el código. Puedo ver una declaración de cambio sin un valor predeterminado y saber que el valor predeterminado es no hacer nada. Agregar desorden no hace que esto sea más obvio.
Robert Noack
Exactamente. Está en el mismo concepto de entregar todos los parámetros. Manejas a los que te importan, no a los demás.
Jimmy Kane
2
@jybrd Si no confía en que el desarrollador anterior omitió el valor predeterminado intencionalmente, ¿por qué confiaría en que fue correcto ponerlo? Un valor predeterminado podría estar accidentalmente vacío, tan fácil como faltar por completo. Un comentario no es necesario para algo tan trivial. Este es el desorden de código. Escriba pruebas de unidad de cobertura completa para mostrar sus intenciones en su lugar. (Solo mi opinión)
Robert Noack
45

NO tener el caso predeterminado puede ser realmente beneficioso en algunas situaciones.

Si sus casos de cambio son valores de enumeración, al no tener un caso predeterminado, puede obtener una advertencia del compilador si falta algún caso. De esa manera, si se agregan nuevos valores de enumeración en el futuro y olvida agregar casos para estos valores en el conmutador, puede averiguar el problema en el momento de la compilación. Todavía debe asegurarse de que el código tome las medidas adecuadas para los valores no controlados, en caso de que se haya emitido un valor no válido al tipo de enumeración. Por lo tanto, esto puede funcionar mejor para casos simples en los que puede regresar dentro del caso enum en lugar de romper.

enum SomeEnum
{
    ENUM_1,
    ENUM_2,
    // More ENUM values may be added in future
};

int foo(SomeEnum value)
{
    switch (value)
    {
    case ENUM_1:
        return 1;
    case ENUM_2:
        return 2;
    }
    // handle invalid values here
    return 0;
 }
Harlan Kassler
fuente
¡Esta es una observación importante! Se aplica aún más en Java porque no le permite lanzar entradas a enumeraciones.
Lii
2
En su ejemplo, podría lanzar una excepción en lugar de regresar después de la instrucción switch. De esa manera, podría tener una comprobación estática por parte del compilador y obtener un error claro si ocurre algo inesperado.
Lii
1
Estoy de acuerdo. En Swift, por ejemplo, el interruptor debe ser exhaustivo; de lo contrario, se obtiene un error del compilador. Proporcionar un valor predeterminado simplemente silencia este útil error. Por otro lado, proporcionar un valor predeterminado si todos los casos se manejan en realidad arroja una advertencia del compilador (declaración inalcanzable).
Andy
1
Solo solucioné un error, eso habría provocado una advertencia del compilador si no hubiera un valor predeterminado: por lo tanto, en general, las Variables de cambio de enumeración no deberían tener un valor predeterminado.
notan
42

Siempre usaría una cláusula predeterminada, sin importar en qué idioma esté trabajando.

Las cosas pueden y salen mal. Los valores no serán lo que espera, y así sucesivamente.

No querer incluir una cláusula predeterminada implica que está seguro de conocer el conjunto de valores posibles. Si crees que conoces el conjunto de valores posibles, entonces, si el valor está fuera de este conjunto de valores posibles, querrás que te informen, es ciertamente un error.

Esa es la razón por la que siempre debe usar una cláusula predeterminada y arrojar un error, por ejemplo en Java:

switch (myVar) {
   case 1: ......; break;
   case 2: ......; break;
   default: throw new RuntimeException("unreachable");
}

No hay razón para incluir más información que solo la cadena "inalcanzable"; si realmente sucede, tendrá que mirar el origen y los valores de las variables, etc. de todos modos, y el stacktrace de excepción incluirá ese número de línea, por lo que no necesita perder el tiempo escribiendo más texto en el mensaje de excepción.

Adrian Smith
fuente
39
Preferiría throw new RuntimeException("myVar invalid " + myVar);ya que eso podría darle suficiente información para descubrir y corregir el error sin tener que usar un depurador e inspeccionar variables, lo que puede ser difícil si este es un problema que rara vez se produce y que es difícil de reproducir.
Chris Dodd
1
¿Qué sucede si no se trata de una condición de error para que el valor no coincida con uno de los casos?
Gabe
44
Si no es una condición de error, entonces no habría necesidad de a default:. Pero más a menudo que no, uno deja de lado un valor predeterminado porque uno piensa myVarque nunca puede tener ningún valor distinto de los enumerados; Sin embargo, no puedo contar la cantidad de veces que me he sorprendido en la vida real cuando la variable ha tenido un valor diferente a los valores que "posiblemente" podría tener. En esos casos, he agradecido la excepción que me hizo ver eso de inmediato, en lugar de causar algún otro error más tarde (más difícil de depurar) o una respuesta incorrecta (podría pasarse por alto en las pruebas).
Adrian Smith el
2
Estoy de acuerdo con Adrian. Falla mucho y falla temprano.
Slappy
Prefiero lanzar un en AssertionErrorlugar de RuntimeException, ya que esta situación es muy similar a una afirmación que indica que myVares uno de los valores manejados. También la posibilidad de que alguien atrape y se trague el error es menor.
Philipp Wendler
15

En mi empresa, escribimos software para el mercado de aviónica y defensa, y siempre incluimos una declaración por defecto, porque TODOS los casos en una declaración de cambio deben manejarse explícitamente (incluso si es solo un comentario que dice 'No hacer nada'). No podemos permitirnos que el software se comporte mal o simplemente se estrelle con valores inesperados (o incluso lo que creemos imposible).

Se puede discutir que un caso predeterminado no siempre es necesario, pero al requerirlo siempre, nuestros analizadores de código lo verifican fácilmente.

Kurt Pattyn
fuente
1
Tengo el mismo requisito donde trabajo; escribimos código para µControllers integrados que tienen que pasar estrictos controles de seguridad y, a menudo, están sujetos a EMI. Sería irresponsable suponer que una variable enumerada nunca tendrá un valor que no esté en la lista de enumeración.
oosterwal
12

¿Debería una declaración de "cambio" incluir siempre una cláusula predeterminada? No. Por lo general, debe incluir un valor predeterminado.

Incluir una cláusula predeterminada solo tiene sentido si tiene algo que hacer, como afirmar una condición de error o proporcionar un comportamiento predeterminado. Incluyendo uno "solo porque" es la programación de culto de carga y no proporciona ningún valor. Es el "cambio" equivalente a decir que todas las declaraciones "if" deben incluir un "else".

Aquí hay un ejemplo trivial de dónde no tiene sentido:

void PrintSign(int i)
{
    switch (Math.Sign(i))
    {
    case 1:
        Console.Write("positive ");
        break;
    case -1:
        Console.Write("negative ");
        break;
    default: // useless
    }
    Console.Write("integer");
}

Este es el equivalente de:

void PrintSign(int i)
{
    int sgn = Math.Sign(i);
    if (sgn == 1)
        Console.Write("positive ");
    else if (sgn == -1)
        Console.Write("negative ");
    else // also useless
    {
    }
    Console.Write("integer");
}
Gabe
fuente
Estoy en desacuerdo. En mi humilde opinión, el único momento en que no debería existir un valor predeterminado es si no hay forma, por ahora y para siempre, de que el conjunto de entradas puede cambiar, y usted tiene cubiertos todos los valores posibles. El caso más simple que se me ocurre es un valor booleano de una base de datos, donde las únicas respuestas (¡hasta que cambie SQL!) Son verdaderas, falsas y NULL. En cualquier otro caso, tener un valor predeterminado con una afirmación o excepción de "¡No debería suceder!" tiene sentido Si su código cambia y tiene uno o más valores nuevos, puede asegurarse de codificarlos y sus pruebas explotarán si no lo hace.
Harper Shelby
44
@ Harper: su ejemplo se incluye en la categoría de "afirmar una condición de error".
Gabe
Yo afirmaría que mi ejemplo es la norma, y ​​que la pequeña cantidad de casos en los que uno puede estar 100% seguro de que todos los casos posibles están cubiertos y no se necesita un defecto es la excepción. Su respuesta está redactada de una manera que suena (al menos para mí) como si la omisión de no hacer nada ocurriera con mayor frecuencia.
Harper Shelby
@ Harper: OK, cambié la redacción para indicar que la situación de no hacer nada es menos común.
Gabe
44
Creo que a default:en esos casos codifica sus suposiciones. Por ejemplo, ¿está bien cuándo sgn==0imprimir integer(ni positivo ni negativo) o es un error? Para mí leer ese código, es difícil de decir. Supongo que no querría escribir zeroen ese caso integer, y que el programador asumió que sgnsolo puede ser -1 o +1. Si ese fuera el caso, tener el default:permitiría al programador detectar el error de suposición antes y cambiar el código.
Adrian Smith el
7

Por lo que veo, la respuesta es 'predeterminado' es opcional, decir que un interruptor siempre debe contener un valor predeterminado es como decir que cada 'if-elseif' debe contener un 'else'. Si hay una lógica que hacer por defecto, entonces la declaración 'default' debería estar allí, pero de lo contrario el código podría continuar ejecutándose sin hacer nada.

Gershon Herczeg
fuente
6

Tener una cláusula predeterminada cuando realmente no es necesaria es una programación defensiva. Esto generalmente conduce a un código que es demasiado complejo debido a un código de manejo de errores excesivo. Este código de detección y manejo de errores daña la legibilidad del código, dificulta el mantenimiento y eventualmente genera más errores de los que resuelve.

Así que creo que si no se alcanza el valor predeterminado, no tiene que agregarlo.

Tenga en cuenta que "no se debe alcanzar" significa que si se alcanza es un error en el software, debe probar los valores que pueden contener valores no deseados debido a la entrada del usuario, etc.

Ophir Yoktan
fuente
3
Otra razón común para obtener casos inesperados: otras partes del código se modifican, tal vez años después.
Hendrik Brummermann
De hecho, este es un comportamiento muy dañino. Al menos, agregaría una cláusula afirmar (). Entonces se detecta fácilmente cada vez que hay un error.
Kurt Pattyn
5

Diría que depende del lenguaje, pero en C si está cambiando un tipo de enumeración y maneja todos los valores posibles, probablemente sea mejor NO incluir un caso predeterminado. De esa manera, si agrega una etiqueta de enumeración adicional más tarde y olvida agregarla al conmutador, un compilador competente le dará una advertencia sobre el caso perdido.

Chris Dodd
fuente
55
Es improbable que "todos los valores posibles" se manejen con enumeraciones. Puede convertir un entero en una enumeración incluso si ese valor en particular no está explícitamente definido. ¿Y qué compilador advierte sobre el caso perdido?
TrueWill
1
@TrueWill: Sí, puede usar conversiones explícitas para escribir código ofuscado que es imposible de entender; para escribir código comprensible, debes evitar eso. gcc -Wall(una especie del mínimo común denominador de compiladores competentes) ofrece advertencias sobre enumeraciones no controladas en las declaraciones de cambio.
Chris Dodd
4

Si sabe que la declaración de cambio solo tendrá un conjunto estrictamente definido de etiquetas o valores, simplemente haga esto para cubrir las bases, de esa manera siempre obtendrá un resultado válido. Simplemente coloque el valor predeterminado sobre la etiqueta que sería programática / lógicamente ser el mejor manejador para otros valores.

switch(ResponseValue)
{
    default:
    case No:
        return false;
    case Yes;
        return true;
}
deegee
fuente
¿ defaultAún se requiere el colon después ? ¿O hacer esto permite una sintaxis especial que le permitió omitirla?
Ponkadoodle
Se requiere el colon, eso fue un error tipográfico, gracias por llamar mi atención.
deegee
3

Al menos no es obligatorio en Java. Según JLS, dice que casi un caso predeterminado puede estar presente. Lo que significa que no se acepta ningún caso predeterminado. A veces también depende del contexto en el que está utilizando la instrucción switch. Por ejemplo, en Java, el siguiente bloque de interruptores no requiere un caso predeterminado

private static void switch1(String name) {
    switch (name) {
    case "Monday":
        System.out.println("Monday");
        break;
    case "Tuesday":
        System.out.println("Tuesday");
        break;
    }
}

Pero en el siguiente método que espera devolver una Cadena, el caso predeterminado es útil para evitar errores de compilación

    private static String switch2(String name) {
    switch (name) {
    case "Monday":
        System.out.println("Monday");
        return name;

    case "Tuesday":
        System.out.println("Tuesday");
        return name;

    default:
        return name;
    }
}

aunque puede evitar el error de compilación para el método anterior sin tener un caso predeterminado con solo tener una declaración de devolución al final, pero proporcionar un caso predeterminado lo hace más legible.

Shiva Kumar
fuente
3

Algunas pautas (obsoletas) lo dicen, como MISRA C :

El requisito para una cláusula predeterminada final es la programación defensiva. Esta cláusula tomará las medidas apropiadas o contendrá un comentario adecuado sobre por qué no se toman medidas.

Ese consejo está desactualizado porque no se basa en criterios actualmente relevantes. La omisión deslumbrante es lo que dijo Harlan Kassler:

Dejar de lado el caso predeterminado permite al compilador opcionalmente advertir o fallar cuando ve un caso no manejado. La verificabilidad estática es, después de todo, mejor que cualquier verificación dinámica y, por lo tanto, no es un sacrificio digno para cuando también se necesita la verificación dinámica.

Como Harlan también demostró, el equivalente funcional de un caso predeterminado puede recrearse después del cambio. Lo cual es trivial cuando cada caso es un retorno temprano.

La necesidad típica de una verificación dinámica es el manejo de entradas, en un sentido amplio. Si un valor proviene de fuera del control del programa, no se puede confiar en él.

Aquí también es donde Misra toma el punto de vista de la programación defensiva extrema, por lo que siempre que un valor no válido sea físicamente representable, debe verificarse, sin importar si el programa es demostrablemente correcto. Lo cual tiene sentido si el software necesita ser lo más confiable posible en presencia de errores de hardware. Pero como dijo Ophir Yoktan, es mejor que la mayoría de los programas no "manejen" los errores. La última práctica a veces se llama programación ofensiva .

usuario2394284
fuente
2

Debería tener un valor predeterminado para detectar los valores no esperados.

Sin embargo, no estoy de acuerdo con Adrian Smith en que su mensaje de error por defecto debería ser algo totalmente sin sentido. Puede haber un caso no manejado que no previó (lo cual es un punto) que su usuario terminará viendo y un mensaje como "inalcanzable" no tiene ningún sentido y no ayuda a nadie en esa situación.

Caso en cuestión, ¿cuántas veces has tenido un BSOD completamente sin sentido? ¿O una excepción fatal @ 0x352FBB3C32342?

John Hunt
fuente
por ejemplo, recuerde que no solo el desarrollador siempre ve mensajes de error. Vivimos en el mundo real, la gente comete errores.
John Hunt
2

Si el valor del interruptor ( interruptor (variable )) no puede alcanzar el caso predeterminado, entonces el caso predeterminado no es necesario. Incluso si mantenemos el caso predeterminado, no se ejecuta en absoluto. Es un código muerto.

shiju
fuente
2

Es una 'convención' de codificación opcional. Dependiendo del uso es si es necesario o no. Personalmente, creo que si no lo necesita, no debería estar allí. ¿Por qué incluir algo que el usuario no utilizará o alcanzará?

Si las posibilidades del caso son limitadas (es decir, un booleano), ¡la cláusula predeterminada es redundante !

Danny Mahoney
fuente
2

Si no hay un caso predeterminado en una switchdeclaración, el comportamiento puede ser impredecible si ese caso surge en algún momento, lo que no era predecible en la etapa de desarrollo. Es una buena práctica incluir un defaultcaso.

switch ( x ){
  case 0 : { - - - -}
  case 1 : { - - - -}
}

/* What happens if case 2 arises and there is a pointer
* initialization to be made in the cases . In such a case ,
* we can end up with a NULL dereference */

Tal práctica puede provocar un error como la anulación de la referencia NULL , pérdida de memoria y otros tipos de errores graves .

Por ejemplo, suponemos que cada condición inicializa un puntero. Pero si defaultse supone que surge un caso y si no lo inicializamos en este caso, entonces hay todas las posibilidades de aterrizar con una excepción de puntero nulo. Por lo tanto, se sugiere utilizar una defaultdeclaración de caso, aunque pueda ser trivial.

Trevor
fuente
2

El caso predeterminado puede no ser necesario en el conmutador utilizado por enum. cuando el interruptor contenía todo el valor, el caso predeterminado nunca se ejecutará. Entonces, en este caso, no es necesario.

estoy bien
fuente
1

Depende de cómo funciona el conmutador en un idioma en particular, sin embargo, en la mayoría de los idiomas, cuando ningún caso coincide, la ejecución cae a través de la declaración del conmutador sin previo aviso. Imagine que esperaba un conjunto de valores y los manejó en el interruptor, sin embargo, obtiene otro valor en la entrada. No pasa nada y no sabes que no pasó nada. Si detecta el caso por defecto, sabría que algo anda mal.

Gabriel Ščerbák
fuente
1

No estoy de acuerdo con la respuesta más votada de Vanwaril arriba.

Cualquier código agrega complejidad. También se deben hacer pruebas y documentación para ello. Por lo tanto, siempre es bueno si puede programar con menos código. Mi opinión es que uso una cláusula predeterminada para declaraciones de cambio no exhaustivas, mientras que no uso una cláusula predeterminada para declaraciones de cambio exhaustivas. Para estar seguro de haberlo hecho bien, uso una herramienta de análisis de código estático. Así que vamos a los detalles:

  1. Sentencias de cambio no exhaustivo: siempre deben tener un valor predeterminado. Como su nombre indica, esas son declaraciones que no cubren todos los valores posibles. Esto también podría no ser posible, por ejemplo, una declaración de cambio en un valor entero o en una cadena. Aquí me gustaría usar el ejemplo de Vanwaril (Cabe mencionar que creo que él usó este ejemplo para hacer una sugerencia incorrecta. Lo uso aquí para decir lo contrario -> Usar una declaración predeterminada):

    switch(keystroke)
    {
      case 'w':
        // move up
      case 'a':
        // move left
      case 's':
        // move down
      case 'd':
        // move right
      default:          
        // cover all other values of the non-exhaustive switch statement
    }
    

    El jugador podría presionar cualquier otra tecla. Entonces no podríamos hacer nada (esto se puede mostrar en el código simplemente agregando un comentario al caso predeterminado) o debería, por ejemplo, imprimir algo en la pantalla. Este caso es relevante ya que puede suceder.

  2. Declaraciones de cambio exhaustivas: esas declaraciones de cambio cubren todos los valores posibles, por ejemplo, una declaración de cambio en una enumeración de tipos de sistemas de calificación. Al desarrollar código la primera vez, es fácil cubrir todos los valores. Sin embargo, como somos humanos, existe una pequeña posibilidad de olvidar algunos. Además, si agrega un valor de enumeración más adelante, de modo que todas las instrucciones de cambio tengan que adaptarse para que sean exhaustivas, nuevamente se abre el camino al infierno de errores. La solución simple es una herramienta de análisis de código estático. La herramienta debe verificar todas las declaraciones de cambio y verificar si son exhaustivas o si tienen un valor predeterminado. Aquí un ejemplo de una declaración exhaustiva de cambio. Primero necesitamos una enumeración:

    public enum GradeSystemType {System1To6, SystemAToD, System0To100}
    

    Entonces necesitamos una variable de esta enumeración como GradeSystemType type = .... Una declaración de cambio exhaustiva se vería así:

    switch(type)
    {
      case GradeSystemType.System1To6:
        // do something
      case GradeSystemType.SystemAToD:
        // do something
      case GradeSystemType.System0To100:
        // do something
    }
    

    Entonces, si ampliamos el, GradeSystemTypepor ejemplo, System1To3la herramienta de análisis de código estático debería detectar que no hay una cláusula predeterminada y que la declaración de cambio no es exhaustiva, por lo que estamos guardados.

Solo una cosa adicional. Si siempre usamos una defaultcláusula, podría suceder que la herramienta de análisis de código estático no sea capaz de detectar sentencias de cambio exhaustivas o no exhaustivas, ya que siempre detecta la defaultcláusula. Esto es súper malo ya que no seremos informados si ampliamos la enumeración por otro valor y olvidamos agregarlo a una declaración de cambio.

Ceniza
fuente
0

¿Las declaraciones de cambio siempre deben contener una cláusula predeterminada? No pueden existir casos de cambio sin el caso predeterminado, en el caso de cambio el caso predeterminado activará el valor del cambio switch(x)en este caso x cuando no coincida con ningún otro valor de caso.

Nisal Edu
fuente
0

Creo que esto es bastante específico del lenguaje y para el caso de C ++ un punto menor para el tipo de clase enum . Que parece más seguro que el tradicional enum. PERO

Si observa la implementación de std :: byte es algo así como:

enum class byte : unsigned char {} ;

Fuente: https://en.cppreference.com/w/cpp/language/enum

Y también considere esto:

De lo contrario, si T es un tipo de enumeración con ámbito o sin ámbito con un tipo subyacente fijo, y si la lista de inicialización arriostrada solo tiene un inicializador, y si la conversión del inicializador al tipo subyacente no es estrecha, y si la inicialización es direct-list-initialization, luego la enumeración se inicializa con el resultado de convertir el inicializador a su tipo subyacente.

(desde C ++ 17)

Fuente: https://en.cppreference.com/w/cpp/language/list_initialization

Este es un ejemplo de clase enum que representa valores que no son enumeradores definidos. Por esta razón, no puede confiar completamente en las enumeraciones. Dependiendo de la aplicación, esto puede ser importante.

Sin embargo, realmente me gusta lo que dijo @Harlan Kassler en su publicación y comenzaré a usar esa estrategia en algunas situaciones.

Solo un ejemplo de clase enum insegura:

enum class Numbers : unsigned
{
    One = 1u,
    Two = 2u
};

int main()
{
    Numbers zero{ 0u };
    return 0;
}
David Ledger
fuente