2011-03-17 19 views
5

Todo lo que me han dicho es que ir a es malo y mantenerse alejado de ellos, pero creo que me pueden ayudar aquí (?). Me gustaría brindarle al usuario la opción de reiniciar la aplicación cuando se detecta una excepción y tengo un poco de problema para decidir qué hacer ...¿Está bien usar "ir a" de una declaración de catch

Mi aplicación será monitoreada por otro proceso, pero hay Hay algunas excepciones en las que quiero que el usuario pueda decidir qué hacer sin devolver el control al proceso de llamada.

¿Es algo como esto "aceptable"? ¿Cualquier otra sugerencia?

Gracias tanto!

int main(){ 

    initialize: 
     try{ 
     //do things 
     } 
     catch(...) 
     { 
      cout<<"Would you like to try initializing again?"<<endl; 

      //if yes 
      goto initialize; 

      //if not 
      abort(); //or something... 
     } 

return 0; 
} 
+4

Este furioso odio de goto es extraño. Supongo que es la misma gente que grita optimización prematura en cada publicación sobre optimización. – Inverse

+1

@Inverso: no es culpa nuestra que el 95% de las publicaciones sobre optimización sean prematuras (es decir, antes de la "medida" en "medir, optimizar, medir"). ¿Pero no es eso un * bit * OT? ;-) – DevSolar

Respuesta

4

Sí, técnicamente está bien, pero se aplican consideraciones "consideradas nocivas".

+2

goto nunca está bien, evítalo como la peste. Te morderá cuando tengas un error más adelante. Nunca lo consideres par. – Paul

+4

@Paul: ¿Tiene una comparación de cuántas personas mató a la plaga y cuántas personas usan 'goto' para matar? – sharptooth

+4

'goto' está bien. Es el mecanismo de control de flujo más simple posible, y encontrar el objetivo de salto es más simple que casi cualquier otro. Si evita la repetición, entonces no hay problema con eso; en C++, es casi imposible unirse en nudos usando 'goto' porque en realidad no puedes ir a ninguna parte tan confusamente lo suficientemente lejos como para causar un problema que no tienes. –

7

¿Por qué no me gusta?

while(true){ 
    //Do stuff 
    if(exit){ 
    break; 
    } 
} 

o

continue = true; 
do{ 
    //Do stuff 
    if(exit){ 
    continue = false; 
    } 
}while(continue); 
+0

+1, este es el camino, no es necesario. – murrekatt

+0

¿Cómo volverías al ciclo while si fuera necesario? Además, ¿cuáles son las implicaciones en try/catch? Estoy planeando captar muchos tipos diferentes de excepciones y necesito darle al usuario opciones sobre qué hacer ... – JonnyK

+2

@Jon, si necesita saltar y entrar, tiene que separarlo en su propio función, luego simplemente llame a la función cuando la necesite. –

5

usted podría intentar:

int main() 
{ 
    while(true) 
    { 
      try 
      { 
       program(); 
      } 
      catch(std::exception& e) 
      { 
       std::cout << "Start again?" << std::endl; 
       //Check ... 
       if(!go_on) 
        break; 
      } 
    } 
    return 0; 
} 
1

forma normal de manejo de excepciones es en el lugar donde se puede hacer algo. Es obvio que el lugar donde intentas manejarlos no es correcto, ya que debes usar goto.

Por lo tanto, algo como esto:

void mainLoop() // get user settings, process, etc 
{ 
    try 
    { 
    // 1) get user settings 
    // 2) process data 
    // 3) inform of the result 
    } 
    catch(const exception_type & e) 
    { 
    // inform of the error 
    }  
} 

int main() 
{ 
    try 
    { 
    while(true) 
     mainLoop(); 
    } 
    catch(...) 
    { 
    std::cout<<"an unknown exception caught... aborting() " << std::endl; 
    } 
} 
+0

pero si reinicia mainLoop() estará fuera de un bloque try, ¿no? – JonnyK

+0

@Jon Correcto, he reparado el ejemplo –

1

La cita original era (creo) "uso incontrolado de Goto considerada perjudicial". Gotos puede ser útil, pero debe usarse de forma controlada. Hay una técnica de programación, para crear subrutinas de reentrada, dependiendo del estado del programa o de los datos, que positivamente exige saltos dirigidos. Aunque esta técnica bien puede considerarse anticuada, entiendo que todavía se usa, pero está oculta por un lenguaje más moderno y características de compilación. El objetivo del control es que debe detenerse y preguntarse, no solo "¿hay una forma más estructurada de hacer lo mismo" - @Justin? Sino también "¿bajo qué condiciones específicas usaré un goto?" Ser conveniente, probablemente, no sea una condición suficiente para usarlo, sin esta respuesta más amplia.

+3

El problema es que algunos de nosotros hemos estado programando durante décadas, sin encontrar esas "condiciones específicas" ni una sola vez. ¡Deben ser muy raros! –

+1

El enfoque que usó este enfoque fue sustancialmente Jackson Structured Programming. La técnica consistía en diseñar programas de comunicación independientes y luego "invertir" uno de los programas para convertirlo en una serie de subrutinas reentrante y con estado. Esto solo se podía hacer escribiendo el programa llamado con código libre de bucle, y la forma de derivar código libre de bucle era reemplazar constructos de bucle con gotos. Esto fue hecho automáticamente por el preprocesador para (al menos) C, Pascal y Cobol. Este enfoque fue ampliamente utilizado en el Reino Unido y Escandinavia, en muchos proyectos privados, gubernamentales y militares. –

+0

Ok, usar código generado por máquina con gotos es similar al compilador que genera jmp para break y continue. Nunca he escrito ningún gotos, ni siquiera he estado cerca. –

6

A goto puede siempre evitar, dando un código más limpio.

Por cierto, lo mismo vale para break s fuera de un switch. La palabra clave continue es marginalmente menos condenable, porque al menos respeta la condición del bucle circundante.

Es importante detectar excepciones en el lugar correcto, donde puede manejar la condición de manera más efectiva.

Y si una condición resulta inconveniente (como "¿volver a intentarlo?" En mi caso), considere negarlo ("¿fallar?") Para obtener una estructura más limpia.

// Tries until successful, or user interaction demands failure. 
bool initialize() { 
    for (;;) { 
     try { 
      // init code 
      return true; 
     } 
     catch (...) { 
      cout << "Init Failed. Fail Program?" << endl; 
      if (yes) { 
       return false; 
      } 
     } 
    } 
} 

int main() { 
    if (! initialize()) { 
     return EXIT_FAILURE; 
    } 
    // rest of program 
    return EXIT_SUCCESS; 
} 

Notas: Este no utiliza goto o break, y no Recurse (especialmente no desde dentro de un bloque de catch).

+3

finalmente alguien lo hace bien +1 – Paul

+1

¿Un regreso temprano es solo un goto disfrazado? ¡Es una broma! –

+0

@Bo Persson: Trate de dibujar un diagrama de Nassi-Shneiderman de mi regreso temprano vs.las soluciones 'break' critiqué como gotos disfrazados. Verá la diferencia: un retorno temprano abandona todo el bloque, mientras que un salto intenta saltar a una posición diferente en el bloque. En serio. ;-) – DevSolar

Cuestiones relacionadas