2010-02-17 11 views
8

Dato una funzione che restituisce un valore, è possibile uscire dalla funzione data una determinata condizione senza restituire nulla? Se è così, come puoi realizzare questo?Come si "spezza" fuori da una funzione?

Esempio:

int getNumber() 
{ 
    . . . 
} 

Quindi dire che sei in questa funzione. C'è un modo per uscirne senza fare nulla?

+1

Potrebbe aiutarti se spieghi perché vuoi farlo, quindi possiamo essere certi che ti stiamo avvisando correttamente. –

+0

@ Tom: Questa è una domanda semplificata, ma sto cercando di implementare una funzione get per una coda che "non farà nulla" se la coda è vuota. – Brandon

risposta

15

Hai due opzioni: return qualcosa o throw.

int getNumber() 
{ 
    return 3; 
} 

int getNumber() 
{ 
    throw string("Some Var"); 
} 

Se throw, bisogna catch il tipo che avete messo.

int maint(int argc, char ** argc) 
{ 
    try 
    { 
      getNumber(); 
    } 
    catch(string std) 
    { 
      //Your code will execute here if you throw 
    } 
} 
+12

Utilizzare l'alternativa di lancio solo se la restituzione di un valore non è un errore. È difficile analizzare il codice che utilizza le eccezioni di lancio per il normale flusso di codice. – Totonga

+0

sì Ottimo punto questo è un no no come pratica standard. – rerun

+1

E, a proposito, le eccezioni sono piuttosto costose in C++: sia il try block che il throw sono costosi e dovrebbero essere usati solo per errori (cioè in scenari * davvero eccezionali *). –

0

In C++ una funzione deve restituire un valore (tipo valore, riferimento o indirizzo) se specificato nella dichiarazione/definizione della funzione.

1

È possibile generare un'eccezione specificata e rilevarla di conseguenza.

0

È possibile lanciare un exception. Non restituiresti nulla, ma dovrai individuare l'eccezione per determinare cosa fare dopo (potresti sempre ingoiare l'eccezione e non fare nulla per ottenere ciò che desideri).

0

Una riprogettazione del metodo è probabile che in ordine se avete bisogno di uscire da una funzione che è destinata a restituire un valore ... o si può semplicemente restituire un valore di "errore" di qualche tipo.

16

È return; senza valore di ritorno. Il compilatore avviserà, ma potrebbe non essere un errore.

MA, perché mai lo considereresti? Cosa stai cercando di ottenere?

E come si presenta il codice di chiamata? Se è int someVar = getNumber(); allora il valore di someVar non è definito (che è A Bad Thing).

Mi sembra che tu voglia restituire due informazioni, una delle quali ti dice se l'altra è valida.

provare qualcosa di simile

bool GetNumber(int * outputNumber) 
{ 
    if .... 
    { 
     *outputNumber = ...; 
     return true; 
    } 
    else 
    { 
     return false; // contents of outputNumber are undefined 
    } 
} 

int number; 
bool isNumberValid; 
isNumberValid = GetNumber(&number); 
if (isNumberValid) 
    ... do something with number 
+3

Lo standard non richiede mai un errore, ma solo una "diagnostica". Quindi tratta allo stesso modo avvertimenti ed ewrors. Ma non lasciarti ingannare: omettere un valore di ritorno è un errore. – MSalters

+0

+1 nel mio libro, ** tutti ** gli avvisi sono errori. Non li tollero. E questo sarebbe davvero egregio. – Mawg

0

Qual è il vostro caso applicativo concreto?

Se davvero non è necessario restituire nulla e terminare la normale esecuzione della funzione, è possibile lanciare un exception.

È anche possibile restituire qualcosa che il chiamante interpreta come un errore (o "nulla restituito").

Qualunque sia la soluzione, il chiamante deve gestire il caso "niente restituito" separatamente, ad es. intercettare l'eccezione o controllare il valore restituito.

2

alternativa delle eccezioni è il ritorno di codice di stato:

SomeStatusCode YourFunc(int &returnValue) { ... returnValue = SomeValue; return SomeStatusCode.Successful; ... return SomeStatusCode.Fail; } //in main func if(YourFunc(retValue)==SomeStatusCode.Successful) // work with retValue else // nothing to do, show error, etc. </code>
-1

Potreste usare setjmp/longjmp (vedi http://en.wikipedia.org/wiki/Setjmp.h), ma dal punto di vista dell'ingegneria del software si sta meglio utilizzando sia eccezioni o codici di errore, come detto da altri qui .

3

Per float e double esiste un'alternativa ma non per i tipi int.

#include <limits> 

double Get() 
{ 
    // no valid return value 
    return std::numeric_limits<double>::quiet_NaN(); 
} 

double val = Get(); 
if(val != val) { 
    // Retrieved no valid return value 
} 
else { 
    // No NaN retrieved 
} 

Fare attenzione quando si utilizza NaN. Ogni condizione su val sarà vera.

+1

Non sono d'accordo, NaN è un float come qualsiasi altro (in questo contesto). Il valore di qualunque cosa stia tornando potrebbe già essere NaN. Preferisco sempre aggiungere un ulteriore parametro bool out, piuttosto che aggiungere un'ipotesi al contratto tra il chiamante e il chiamato. –

+0

Questo può essere vero o no, ma penso che se ci sono dei NaN usati devi essere consapevole di loro. NaN non è come qualsiasi altro numero perché tutte le condizioni saranno vere. (NaN> 1 && NaN <1 && NaN == 1) valuterà a vero. – Totonga

1

Puoi anche restituire una classe/struttura con una conversione magica utile per le tue esigenze speciali.

esempio reale di vita: una volta ho avuto in realtà tornare due pezzi di informazioni nello stesso valore di ritorno, un valore di segnalare se un messaggio finestra era stata completamente elaborato e il valore da restituire per esso se il trattamento era già completato. Così ho confezionato tutto in una classe come questa:

//This class is used to carry a return value for a window message and a value that indicates if the 
//message has already been completely processed 
class MessageReturnValue 
{ 
public: 
    LRESULT returnValue; 
    bool processed; 
    MessageReturnValue() 
    { 
     processed=false; 
     returnValue=FALSE; 
    }; 
    MessageReturnValue(LRESULT ReturnValue) 
    { 
     processed=true; 
     returnValue=ReturnValue; 
    }; 
    MessageReturnValue(bool Processed) 
    { 
     returnValue=FALSE; 
     processed=Processed; 
    }; 
    inline operator bool() 
    { 
     return processed; 
    }; 
    inline operator LRESULT() 
    { 
     return returnValue; 
    }; 
}; 

Questo mi ha permesso di fare proprio return false; in una funzione che ha restituito un MessageReturnValue se il messaggio fosse ancora da trasformati, o per return TRUE/15/whatever; se il messaggio fosse stato completamente elaborato e ho già avuto un valore di ritorno. Il chiamante, da parte sua, potrebbe semplicemente fare

LRESULT MyWndProc(/* blah blah blah */) 
{ 
    MessageReturnValue ret = MyFunction(/* blah blah blah */); 
    if(!ret) 
    { 
     /* process the message */ 
     return /* something */; 
    } 
    else 
     return (LRESULT)ret; 
} 

Se avete esigenze più complesse, si potrebbe anche considerare l'utilizzo di boost :: tuple.

8

Soluzione semplice:

boost::optional<int> getNumber() 
{ 
    // May now return an int, or may return nothing. 
} 
+0

È necessario restituire qualcosa, anche se è solo un oggetto "vuoto" opzionale . Non restituire nulla causa un comportamento indefinito per tutte le funzioni diverse da quelle principali e quelle che restituiscono nulla. – sellibitze

+1

È un comportamento non definito o un oggetto predefinito costruito (non definito per built-in/pod)? Ad ogni modo +1 per suggerire 'boost :: optional', questo è il modo con i valori opzionali ... –

+0

@sellibitze: ovviamente per questo codice" niente "significa' boost :: opzionale () '. Vedi il commento allegato: "implementa una funzione get per una coda che farà [return] nulla se la coda è vuota". – MSalters

3

Ne fanno un requisito per l'utente di verificare prima che la coda non è vuota (fornire i mezzi per questo).

Quindi è possibile:

  • non controlla nulla e semplicemente invocare comportamento non definito (accesso dati sottostanti come se fosse lì) - è colpa dell'utente
  • controllo e tiro eccezione
  • assert (risultato non è definito con NDEBUG)

Controllare e quindi richiamare un comportamento indefinito (restituendo un valore arbitrario) è la cosa peggiore da fare. Si ottiene sia il sovraccarico di runtime del controllo e il chiamante non è più saggio, in quanto il risultato è ancora indefinito.

+1

+1, la migliore soluzione IMO in questo caso d'uso – sellibitze

+0

Questo è un po 'problematico negli ambienti multi-thread, specialmente se si stanno leggendo più thread. – MSalters

Problemi correlati