¿Por qué evitar el goto
?
El problema que se quiere resolver es: ¿Cómo hacer seguro de que algunos de código común, siempre se ejecuta antes de que la función devuelve a la persona que llama? Esto es un problema para los programadores de C, ya que C no proporciona ningún apoyo para RAII.
Como ya ceder en la cuestión del cuerpo, goto
es una perfecta solución aceptable. Nunca-el-menos, no puede ser no-razones técnicas para evitar el uso de:
- ejercicio académico
- codificación de cumplimiento de la norma
- personal capricho (que creo que es lo que está motivando a esta pregunta)
Siempre hay más de una manera para la piel de un gato, pero la elegancia como un criterio es demasiado subjetiva para proporcionar una manera para limitar a un único mejor alternativa. Usted tiene que decidir cuál es la mejor opción para usted.
Una llamada explícita a una función de limpieza de
Si se evita un explícito saltar (por ejemplo, goto
o break
) común código de limpieza puede ser encapsulado dentro de una función, y se llama explícitamente en el punto de comienzos return
.
int foo () {
...
if (SOME_ERROR) {
return foo_cleanup(SOME_ERROR_CODE, ...);
}
...
}
(Esto es similar a otro publicado respuesta, que sólo la vi después de que inicialmente publicado, pero la forma que se muestra aquí puede tomar ventaja de los hermanos de la llamada optimizaciones.)
Algunas personas sienten lo explícito es más clara, y por lo tanto más elegante. Otros sienten la necesidad de pasar de limpieza de los argumentos de la función a ser un gran detractor.
Añadir otra capa de indirección.
Sin cambiar la semántica del usuario de la API, el cambio de su aplicación en un contenedor compuesto de dos partes. Parte uno realiza el trabajo real de la función. La segunda parte realiza la limpieza necesaria después de la primera parte se hace. Si cada parte está encapsulado dentro de su propia función, la función de contenedor tiene un muy limpio implementación.
struct bar_stuff {...};
static int bar_work (struct bar_stuff *stuff) {
...
if (SOME_ERROR) return SOME_ERROR_CODE;
...
}
int bar () {
struct bar_stuff stuff = {};
int r = bar_work(&stuff);
return bar_cleanup(r, &stuff);
}
El "implícita" de la naturaleza de la limpieza desde el punto de vista de la función que realiza el trabajo puede ser visto favorablemente por algunos. Algunas de las potenciales código de la hinchazón también puede evitarse por sólo llamando a la función de limpieza de un solo lugar. Algunos argumentan que "implícita" conductas son "difíciles", y por lo tanto más difícil de entender y de mantener.
Miscelánea...
Más esotéricas de soluciones mediante el uso de setjmp()
/longjmp()
puede ser considerada, pero utilizando de manera correcta puede ser difícil. No son de código abierto contenedores que implementar try/catch estilo de macros a través de ellos (por ejemplo, cexcept
), pero usted tiene que cambiar su estilo de codificación a utilizar ese estilo para el manejo de errores.
También se podría considerar la aplicación de la función como una máquina de estado. La función de progreso a través de cada estado, un error hace que la función de corto circuito para la limpieza de estado. Este estilo es generalmente reservado particularmente complejos, funciones o funciones que deben ser intentar más tarde y ser capaz de recoger, desde donde la dejaron.
Hacer como los Romanos.
Si usted necesita para cumplir con los estándares de codificación, a continuación, el mejor enfoque es seguir lo que técnica es la más frecuente en la base del código existente. Esto se aplica a casi todos los aspectos de hacer cambios en los existentes estable base de código fuente. Se considera perjudicial para introducir un nuevo estilo de codificación. Usted debe buscar la aprobación de los poderes que si usted se siente un cambio dramáticamente mejorar algún aspecto del software. De lo contrario, como la "elegancia" es subjetiva, argumentando que por el bien de la "elegancia" no va a llegar a ninguna parte.