Come gestire le uscite di funzione su una funzione che ha diversi punti di uscita?

Sono più uno studente di quanto non sia un programmatore esperto e l’altro giorno ho rifatto un pezzo di codice che ho scritto qualche tempo fa. Lì dentro c’era una funzione che era piuttosto grande nelle dimensioni del codice e aveva una struttura come questa:

if (eval) return code; ... if (different test) return another code; ... 

In tutto c’erano circa 6 o 7 punti di ritorno, alcuni dei quali con codice di pulizia all’interno del ramo. Alcuni di essi hanno anche risposto a situazioni errate, percorsi in cui la funzione non avrebbe elaborato completamente l’input, ma avrebbe restituito un codice di errore.

Anche se il codice è stato commentato e tutto mi è sembrato difficile per gli occhi e difficile da leggere. Quindi mi chiedevo se ci sono delle buone pratiche in materia.

Leggendo il codice da tutta la rete ho trovato diversi approcci a questo argomento. Ad esempio si seguirebbe questo schema:

 do { whole body of the function; while (false); clean up code if necessary; return code; 

Principalmente essere in grado di usare la break; frasi in diverse valutazioni (dato che eravamo all’interno di un ciclo) per uscire dal ciclo, effettuare la pulizia se necessario e restituire il codice di uscita. Ma mi sembra lo stesso di goto s per me, con la limitazione a cui si rivolgono per andare avanti nel codice.

Un altro sarebbe simile al mio, ma ha solo una dichiarazione di return alla fine della funzione e una variabile per contenere i codici di errore.

Puoi usare goto per quello.

 code = firstCode; if (condition != 0) goto label; code = secondCode; if (anotherCondition != 0) goto label; label: clean_up_code_if_necessary() exit(code); // may be you should return from the function 

ma potrebbero esserci molte altre opzioni a seconda del caso specifico.

Qui è usato frequentemente il linguaggio del kernel di Linux. Quando qualcosa non funziona, ripristina e ripulisce il codice precedentemente eseguito.

 if(do_a()==FAIL) goto fail_a; if(do_b()==FAIL) goto fail_c; if(do_c()==FAIL) goto fail_c; /* rest of the code goes here */ /* if it's ok then set err to 0 and jump to ok */ err = 0; goto ok; // otherwise unroll what have been done fail_c: undo_c(); fail_b: undo_b(); fail_a: undo_a(); ok: return err; 

beh, abbiamo bisogno di distinguere tra C e C ++, il modo di gestire le cose è abbastanza diverso tra C e C ++.

In C, raccomanderei di utilizzare un Enum che indica lo stato corrente del codice, ad esempio:

 enum {State1,State2,Invalid_Argument,Error} 

quindi, creare una funzione che controlli ciò di cui ha bisogno, quindi restituire alcuni costanti dall’enum sopra come valore di ritorno:

 int check_statement(arg1,arg2...) 

e, infine, utilizzare un interruttore caso sulla funzione sopra:

  switch(check_statment(...)){ case state1: ... return ... case Error: ... return.. }