c++ - para - manual de programacion android pdf
Ejemplos de buenos gotos en C o C++ (16)
@ fizzer.myopenid.com: el fragmento de código publicado es equivalente a lo siguiente:
while (system_call() == -1)
{
if (errno != EINTR)
{
// handle real errors
break;
}
}
Definitivamente prefiero esta forma.
En este hilo, vemos ejemplos de buenos usos de goto
en C o C ++. Está inspirado en una respuesta que la gente votó porque pensaban que estaba bromeando.
Resumen (etiqueta cambiada del original para hacer la intención aún más clara):
infinite_loop:
// code goes here
goto infinite_loop;
Por qué es mejor que las alternativas:
- Es específico.
goto
es la construcción del lenguaje que causa una rama incondicional. Las alternativas dependen del uso de estructuras que soporten ramas condicionales, con una condición degenerada siempre verdadera. - La etiqueta documenta la intención sin comentarios adicionales.
- El lector no tiene que escanear el código intermedio para los primeros
break
(aunque todavía es posible que un hacker sin principios simulecontinue
con ungoto
temprano).
Reglas:
- Pretenda que los gotophobes no ganaron. Se entiende que lo anterior no se puede usar en código real porque va en contra del idioma establecido.
- Supongamos que todos hemos oído hablar de ''Goto considerado dañino'' y sabemos que goto puede usarse para escribir código de espagueti.
- Si no está de acuerdo con un ejemplo, critíquelo únicamente por mérito técnico ("porque a la gente no le gusta el goto" no es una razón técnica).
Veamos si podemos hablar de esto como adultos.
Editar
Esta pregunta parece terminada ahora. Generó algunas respuestas de alta calidad. Gracias a todos, especialmente a aquellos que tomaron en serio mi pequeño ejemplo de loop. La mayoría de los escépticos estaban preocupados por la falta de alcance del bloque. Como señaló @quinmars en un comentario, siempre puedes poner llaves alrededor del cuerpo del bucle. Noto de paso que for(;;)
y while(true)
tampoco te dan llaves (y omitirlas puede causar molestos errores). De todos modos, no perderé más de tu poder mental en esta bagatela: puedo vivir con lo inofensivo y lo idiomático for(;;)
y while(true)
(igual de bien si quiero mantener mi trabajo).
Considerando las otras respuestas, veo que muchas personas ven el goto
como algo que siempre debes reescribir de otra manera. Por supuesto, puedes evitar un goto
introduciendo un bucle, una bandera extra, una pila de anidados if
, o lo que sea, pero ¿por qué no considerar si goto
es quizás la mejor herramienta para el trabajo? Dicho de otra manera, ¿qué fealdad está dispuesta a soportar la gente para evitar el uso de una función de idioma incorporada para su propósito previsto? Mi opinión es que incluso agregar una bandera es un precio demasiado alto para pagar. Me gustan mis variables para representar cosas en el problema o los dominios de la solución. ''Solo para evitar un goto
'' no lo corta.
Aceptaré la primera respuesta, que dio el patrón C para la bifurcación a un bloque de limpieza. OMI, este es el caso más fuerte para un goto
de todas las respuestas publicadas, ciertamente si lo mides por las contorsiones que un enemigo tiene que pasar para evitarlo.
@Greg:
Por qué no hacer tu ejemplo así:
void foo()
{
if (doA())
{
if (doB())
{
if (!doC())
{
UndoA();
UndoB();
}
}
else
{
UndoA();
}
}
return;
}
Aquí está mi ejemplo no tonto, (de Stevens APITUE) para llamadas al sistema Unix que pueden ser interrumpidas por una señal.
restart:
if (system_call() == -1) {
if (errno == EINTR) goto restart;
// handle real errors
}
La alternativa es un ciclo degenerado. Esta versión se lee en inglés "si la llamada al sistema fue interrumpida por una señal, reiníciela".
Aquí hay un ejemplo de un buen goto:
// No Code
Aunque he llegado a odiar este patrón con el tiempo, está integrado en la programación COM.
#define IfFailGo(x) {hr = (x); if (FAILED(hr)) goto Error}
...
HRESULT SomeMethod(IFoo* pFoo) {
HRESULT hr = S_OK;
IfFailGo( pFoo->PerformAction() );
IfFailGo( pFoo->SomeOtherAction() );
Error:
return hr;
}
Este es un truco que escuché de gente usando. Aunque nunca lo había visto en la naturaleza. Y solo se aplica a C porque C ++ tiene RAII para hacer esto de manera más idiomática.
void foo()
{
if (!doA())
goto exit;
if (!doB())
goto cleanupA;
if (!doC())
goto cleanupB;
/* everything has succeeded */
return;
cleanupB:
undoB();
cleanupA:
undoA();
exit:
return;
}
He visto goto usado correctamente, pero las situaciones son normalmente feas. Es solo cuando el uso de goto
es mucho peor que el original. @Johnathon Holland, el problema es que tu versión es menos clara. las personas parecen tener miedo de las variables locales:
void foo()
{
bool doAsuccess = doA();
bool doBsuccess = doAsuccess && doB();
bool doCsuccess = doBsuccess && doC();
if (!doCsuccess)
{
if (doBsuccess)
undoB();
if (doAsuccess)
undoA();
}
}
Y prefiero bucles como este, pero algunas personas prefieren while(true)
.
for (;;)
{
//code goes here
}
Knuth ha escrito un documento "Programación estructurada con declaraciones GOTO", puede obtenerlo, por ejemplo, desde here . Encontrarás muchos ejemplos allí.
La necesidad clásica de GOTO en C es la siguiente
for ...
for ...
if(breakout_condition)
goto final;
final:
No hay una forma sencilla de salir de los bucles anidados sin un goto.
Mi queja sobre esto es que pierdes el alcance del bloque; cualquier variable local declarada entre los gotos permanece vigente si el bucle se rompe alguna vez. (Tal vez suponga que el ciclo se ejecuta para siempre, pero no creo que eso fuera lo que el autor de la pregunta original estaba formulando).
El problema del alcance es más un problema con C ++, ya que algunos objetos pueden ser dependientes de que se llame a su controlador en los momentos apropiados.
Para mí, la mejor razón para usar goto es durante un proceso de inicialización de varios pasos donde es vital que todas las entradas sean restituidas si falla, a la la:
if(!foo_init())
goto bye;
if(!bar_init())
goto foo_bye;
if(!xyzzy_init())
goto bar_bye;
return TRUE;
bar_bye:
bar_terminate();
foo_bye:
foo_terminate();
bye:
return FALSE;
Muy común.
do_stuff(thingy) {
lock(thingy);
foo;
if (foo failed) {
status = -EFOO;
goto OUT;
}
bar;
if (bar failed) {
status = -EBAR;
goto OUT;
}
do_stuff_to(thingy);
OUT:
unlock(thingy);
return status;
}
El único caso que uso goto
es saltar hacia adelante, generalmente fuera de bloques, y nunca en bloques. Esto evita el uso indebido de do{}while(0)
y otras construcciones que aumentan la anidación, al tiempo que mantienen un código legible y estructurado.
No tengo nada en contra de los gotos en general, pero puedo pensar en varias razones por las que no querrás usarlos para un ciclo como el que mencionas:
- No limita el alcance, por lo tanto, las variables temporales que utilice en su interior no se liberarán hasta más adelante.
- No limita el alcance, por lo tanto, podría provocar errores.
- No limita el alcance, por lo tanto, no puede volver a utilizar los mismos nombres de variable más adelante en el código futuro en el mismo ámbito.
- No limita el alcance, por lo tanto, tiene la posibilidad de omitir una declaración de variable.
- La gente no está acostumbrada y hará que su código sea más difícil de leer.
- Los bucles anidados de este tipo pueden conducir al código de spaghetti, los bucles normales no conducirán al código de spaghetti.
No uso goto yo mismo, sin embargo, sí trabajé con una persona una vez que los usaría en casos específicos. Si mal no recuerdo, su razón de ser era sobre problemas de rendimiento, también tenía reglas específicas de cómo hacerlo . Siempre en la misma función, y la etiqueta siempre estaba ABAJO de la declaración goto.
Si el dispositivo de Duff no necesita un goto, ¡tampoco tú deberías! ;)
void dsend(int count) {
int n;
if (!count) return;
n = (count + 7) / 8;
switch (count % 8) {
case 0: do { puts("case 0");
case 7: puts("case 7");
case 6: puts("case 6");
case 5: puts("case 5");
case 4: puts("case 4");
case 3: puts("case 3");
case 2: puts("case 2");
case 1: puts("case 1");
} while (--n > 0);
}
}
código arriba de la entry Wikipedia.
Un buen lugar para usar un goto es en un procedimiento que puede abortar en varios puntos, cada uno de los cuales requiere varios niveles de limpieza. Gotophobes siempre puede reemplazar los gotos con código estructurado y una serie de pruebas, pero creo que esto es más sencillo porque elimina la indentación excesiva:
if (!openDataFile()) goto quit; if (!getDataFromFile()) goto closeFileAndQuit; if (!allocateSomeResources) goto freeResourcesAndQuit; // Do more work here.... freeResourcesAndQuit: // free resources closeFileAndQuit: // close file quit: // quit!
#include <stdio.h>
#include <string.h>
int main()
{
char name[64];
char url[80]; /*The final url name with http://www..com*/
char *pName;
int x;
pName = name;
INPUT:
printf("/nWrite the name of a web page (Without www, http, .com) ");
gets(name);
for(x=0;x<=(strlen(name));x++)
if(*(pName+0) == ''/0'' || *(pName+x) == '' '')
{
printf("Name blank or with spaces!");
getch();
system("cls");
goto INPUT;
}
strcpy(url,"http://www.");
strcat(url,name);
strcat(url,".com");
printf("%s",url);
return(0);
}