In alternativa alla goto-statement in questo caso? [duplicare]

1

Attualmente sto usando gotos per gli handle di chiusura e la pulizia generale se si verifica un errore.
Dal momento che non voglio annidare tutti i if e una funzione per la pulizia richiederebbe un return oltre alla chiamata cleanup(); , non ho ancora nessuna buona idea.

La struttura è così:

if (condition1) {
   goto cleanup;
}

if (condition2) {
   goto cleanup;
}

if (condition3) {
   goto cleanup;
}

// do stuff only if all checks passed

cleanup:
CloseHandle(x);
CloseHandle(y);
// etc.
    
posta Benjoyo 24.03.2015 - 12:50
fonte

3 risposte

6

La pulizia potrebbe essere in una funzione esterna, quindi è possibile utilizzare return anziché goto :

void main_func() {
    /* Set-up goes here */
    handle x = ...;
    handle y = ...;
    void result = inner_func(x, y);

    /* Clean-up goes here */
    CloseHandle(x);
    CloseHandle(y);
}

void inner_func(x, y) {
    if (condition1) return;
    if (condition2) return;
    if (condition3) return;

    /* Do things here */
}

Ma goto per cose come questa non è che cattivo, secondo me.

    
risposta data 24.03.2015 - 13:19
fonte
4

Potresti provare a dire cosa intendi:

if (!condition1
 && !condition2
 && !condition3 ) {

// do stuff only if all checks passed
}
CloseHandle(x);
CloseHandle(y);
// etc.

Come hanno sottolineato vari commentatori, questo è leggibile / gestibile solo se i test di condizione sono abbastanza semplici quando sono coinvolte condizioni complesse come una cosa più pulita: -

if (doAble()) {
   // usefull work here
}
CloseHandle(x);
CloseHandle(y);

boolean doAble() {
  if (condition1) {
     return false;
  }
  if (condition2) {
     return false;
  }
  if (condition3) {
     return false;
  }
  return true;
}

Tuttavia, se hai bisogno di un sacco di variabili locali per valutare le condizioni, anche questo può diventare disordinato.

    
risposta data 24.03.2015 - 17:37
fonte
3

In C un modo tipico per semplificare la verifica degli errori ed evitare il deep nested if è:

do
{
  if (condition1) break;

  /* 1. do something... */

  if (condition2) break;

  /* 2. do something else... */

  if (condition3) break;

  /* 3. do something else... */
} while(0);

/* Cleanup */

Ci sono varie opinioni su questo "idioma" (es. dai un'occhiata a Fai considera questa tecnica "BAD"? ).

Forse dovresti aggiungere un commento su do per rendere chiaro a tutti cosa sta succedendo.

Spesso puoi riscrivere il codice usando una funzione di aiuto e cambiare il do-loop falso in:

void func(X *x, Y *y)
{
  if (condition1) return;

  /* 1. do something... */

  if (condition2) return;

  /* 2. do something else... */

  if (condition3) return;

  /* 3. do something else... */
}


/* ... */
X x;
Y y;

func(&x, &y);

/* Cleanup */

e non sarà considerato una "cattiva pratica" dal momento che è più prevedibile.

Se non hai i passaggi intermedi ( 1. e 2. ) questo è probabilmente sufficiente:

int stop = condition1 || condition2 || condition3;

if (!stop)
{
  /* ... */
}

/* Cleanup */
    
risposta data 24.03.2015 - 12:59
fonte

Leggi altre domande sui tag