squalyl (./6) :
Godzil: ça dépend de la durée de vie du process... Pour un démon par exemple, vaut mieux fermer proprement quand t'as plus besoin d'une ressource, mais j'ai bien vu que tu parlais des cas exceptionnels. Un cleanup explicite peut quand même servir, par exemple, pour un protocole réseau ou quand tu travailles avec des ressources distantes et qu'un timeout coté serveur n'a pas été prévu (ce n'est pas forcément un bug).
Bien sur c'est pour ça que j'ai précisé pour un exemple d'un fichier ouvert avec des choses écrites, mais sa s'applique des que la sortie brutale d'une app peu impacter des donnée utilisateurs ou d'autres process (qu'ils soit locaux ou distant) je pensais et parlait (pour ne pas se faire chier) que dans le cas ou l'app ne peux que faire un abort violent, et que ça n'a aucune conséquence externe de laisse l'OS nettoyer (et il le ferra mieux qu'une app en train de planter)
Sinon le coup du goto est, *je pense* la meilleurs facons de faire, et le kernel linux en use, et abuse, si l'on puis dire ainsi.
int fonction(char *blah)
{
int ret = FAILED;
if (DoingFoo() == failed)
{
goto exit;
}
char *allocated = CreateSomething();
if (AnotherThing() == failed)
{
goto exit_clean;
}
ret = OK;
goto exit;
exit_clean:
Cleanup(allocated);
exit:
printf("%s: Exiting with ret=%d (allocated = %p)", __FUNC__, ret, allocated);
blah = allocated;
return ret;
}
L'enorme avantage de cette technique, c'est le point de sortie UNIQUE, ou on a besoin de ne mettre qu'une seule fois les affichages/hook/breakpoint de debug on sais qu'on sort toujours de la.
Ensuite, certain decrient goto, et appelent au meutre si on l'utilise, mais goto est une bonne instruction utilise correctement, cad ne pas utilise goto pour remplacer un appel de fonction. La en l'occurent, goto est utilise pour les cas exceptionnel, ou pour sortir rapidement, et proprement, d'une boucle lourde.
(edit: le bug qui met des \ partout pour remplacer des retours chariots existe toujours..)
Exemple ce code du kernel:
static int nkbd_connect(struct serio *serio, struct serio_driver *drv)
{
struct nkbd *nkbd;
struct input_dev *input_dev;
int err = -ENOMEM;
int i;
nkbd = kzalloc(sizeof(struct nkbd), GFP_KERNEL);
input_dev = input_allocate_device();
if (!nkbd || !input_dev)
goto fail1;
nkbd->serio = serio;
nkbd->dev = input_dev;
snprintf(nkbd->phys, sizeof(nkbd->phys), "%s/input0", serio->phys);
memcpy(nkbd->keycode, nkbd_keycode, sizeof(nkbd->keycode));
input_dev->name = "Newton Keyboard";
input_dev->phys = nkbd->phys;
input_dev->id.bustype = BUS_RS232;
input_dev->id.vendor = SERIO_NEWTON;
input_dev->id.product = 0x0001;
input_dev->id.version = 0x0100;
input_dev->dev.parent = &serio->dev;
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
input_dev->keycode = nkbd->keycode;
input_dev->keycodesize = sizeof(unsigned char);
input_dev->keycodemax = ARRAY_SIZE(nkbd_keycode);
for (i = 0; i < 128; i++)
set_bit(nkbd->keycode[i], input_dev->keybit);
clear_bit(0, input_dev->keybit);
serio_set_drvdata(serio, nkbd);
err = serio_open(serio, drv);
if (err)
goto fail2;
err = input_register_device(nkbd->dev);
if (err)
goto fail3;
return 0;
fail3: serio_close(serio);
fail2: serio_set_drvdata(serio, NULL);
fail1: input_free_device(input_dev);
kfree(nkbd);
return err;
}
D'ailleurs la fin aurait pu être 'simplifie' en
if (err)
goto fail3;
err = 0;
goto exit;
fail3: serio_close(serio);
fail2: serio_set_drvdata(serio, NULL);
fail1: input_free_device(input_dev);
kfree(nkbd);
exit: return err;
}