2010-02-17 34 views
8

Dada una función que devuelve un valor, es posible salir de la función dada una determinada condición sin devolver nada? Si es así, ¿cómo puedes lograr esto?¿Cómo se "rompe" una función?

Ejemplo:

int getNumber() 
{ 
    . . . 
} 

lo tanto, decir que está en esta función. ¿Hay alguna manera de salir sin que haga nada?

+1

Puede ser que te ayude si explicas por qué quieres hacer esto, entonces podemos estar seguros de que te estamos asesorando correctamente. –

+0

@Tom: esta es una pregunta simplificada, pero estoy tratando de implementar una función get para una cola que "no hará nada" si la cola está vacía. – Brandon

Respuesta

15

Tiene dos opciones: return algo o .

int getNumber() 
{ 
    return 3; 
} 

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

Si throw, usted tiene que catch del tipo que tiró.

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

Solo use la alternativa de tiro si devolver un valor no es un error. Es difícil de analizar el código que utiliza arrojando excepciones para el flujo de código normal. – Totonga

+0

sí Gran punto, este es un no no como práctica estándar. – rerun

+1

Y, dicho sea de paso, las excepciones son bastante costosas en C++: tanto el bloqueo try como el throw son costosos, y deberían usarse solo para errores (es decir, en escenarios realmente * excepcionales *). –

0

En C++ una función debe devolver un valor (tipo de valor, referencia o dirección) si se especifica uno en la declaración/definición de la función.

1

que podría lanzar una excepción especificada y ponerse en consecuencia.

0

Se podría lanzar una exception. No tendría devolver nada, pero usted tiene que coger la excepción para determinar qué hacer a continuación (siempre se puede tragar la excepción y no hacer nada para conseguir lo que quiere).

0

Un rediseño de su método es probable que con el fin si tiene que salir de una función que es la intención de devolver un valor ... o simplemente puede devolver un valor "error" de algún tipo.

16

Usted podría salirse con un return; sin valor devuelto. El compilador advertirá, pero puede no error.

PERO, ¿por qué demonios considerarías esto? ¿Qué estás intentando lograr?

Y qué hace el código de llamada parece? Si es int someVar = getNumber(); entonces el valor de somevar no está definido (que es una mala cosa).

Me parece que quiere devolver dos datos, uno de los cuales le dice si el otro es válido.

intentar algo así como

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

La norma nunca requiere un error, simplemente un "diagnóstico". Por lo tanto, trata las advertencias y los ewrors por igual. Pero no dejes que te engañe: omitir un valor de retorno _es_ un error. – MSalters

+0

+1 en mi libro ** todas las advertencias son errores. No los toco. Y esto sería realmente atroz. – Mawg

0

¿Cuál es su caso de uso real?

Si realmente no necesita devolver nada y finalizar la ejecución normal de la función, puede lanzar un exception.

También puede devolver algo que la persona que llama interpreta como un error (o 'no ha devuelto nada').

Cualquiera que sea su solución, la persona que llama debe manejar el caso 'nada devuelto' por separado, p. capte la excepción o verifique el valor devuelto.

2

Alternativo de las excepciones es el retorno del código de estado:

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

Usted podría utilizar setjmp/longjmp (ver http://en.wikipedia.org/wiki/Setjmp.h), pero desde una perspectiva de ingeniería de software que es mejor usar cualquiera de las excepciones o códigos de error como han mencionado otros aquí .

3

Para flotante y doble hay una alternativa pero no para tipos 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 
} 

Tenga cuidado al usar NaN. Cada condición en val será verdadera.

+1

No estoy de acuerdo, NaN es una carroza como cualquier otra (en este contexto). El valor de lo que sea que regrese ya puede ser NaN. Siempre prefiero agregar un parámetro de bool out adicional, que agregar una suposición al contrato entre el que llama y el que recibe la llamada. –

+0

Esto puede ser cierto o no, pero creo que si hay algún NaN utilizado, debe tenerlo en cuenta. NaN no es como cualquier otro número porque todas las condiciones serán verdaderas. (NaN> 1 && NaN <1 && NaN == 1) se evaluará como verdadero. – Totonga

1

También podría devolver una clase/estructura con alguna conversión mágica que sea útil para su necesidad especial.

Ejemplo de vida real: una vez tuve que devolver dos piezas de información en el mismo valor devuelto, un valor para informar si un mensaje de ventana había sido procesado por completo y el valor devuelto si el procesamiento ya estaba terminado. Así que empaqué todo en una clase como esta:

//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; 
    }; 
}; 

Esto me permitió hacer simplemente return false; en una función que devuelve un MessageReturnValue si el mensaje aún no se había procesado, o para return TRUE/15/whatever; si el mensaje había sido completamente procesado y ya tuve un valor de retorno. La persona que llama, por su parte, sólo podía hacer

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

Si tiene necesidades más complejas, también se puede considerar el uso de impulso :: tupla.

8

solución simple:

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

Debe devolver algo, incluso si se trata de un objeto opcional "vacío". No devolver nada provoca un comportamiento indefinido para todas las funciones que no sean principales y aquellas que devuelven el vacío. – sellibitze

+1

¿Es un comportamiento indefinido o un objeto construido por defecto (indefinido para built-in/pods)? De todos modos +1 para sugerir 'boost :: optional', ese es el camino con valores opcionales ... –

+0

@sellibitze: por supuesto para este código" nada "significa' boost :: opcional () '. Vea el comentario adjunto: "implemente una función get para una cola que no devolverá [nada] si la cola está vacía". – MSalters

3

Que sea un requisito para que el usuario debe comprobar que la cola no está vacía (proporcionar medios para eso).

A continuación, se puede:

  • no comprueba nada y simplemente invocar un comportamiento indefinido (de acceso subyacente datos como si estaba allí) - que es culpa del usuario
  • cheque y un tiro excepción
  • assert (resultado no está definido con NDEBUG)

Verificar y luego invocar el comportamiento indefinido (devolver un valor arbitrario) es lo peor que se puede hacer. Usted obtiene tanto la sobrecarga en tiempo de ejecución del cheque como la persona que llama no es más prudente, ya que el resultado aún no está definido.

+1

+1, la mejor solución de la OMI en este caso de uso – sellibitze

+0

Esto es un poco problemático en entornos de subprocesos múltiples, especialmente si se están leyendo varios subprocesos. – MSalters

Cuestiones relacionadas