How do you "break" out of a function?
Given a function that returns a value, is it possible to exit the function given a certain condition without returning anything? If so, how can you accomplish this?
开发者_如何学JAVAExample:
int getNumber ()
{
. . .
}
So say you are in this function. Is there a way to exit it without it doing anything?
You have two options: return
something or throw
.
int getNumber()
{
return 3;
}
int getNumber()
{
throw string("Some Var");
}
If you throw
, you have to catch
the type you threw.
int maint(int argc, char ** argc)
{
try
{
getNumber();
}
catch(string std)
{
//Your code will execute here if you throw
}
}
You might get away with a return;
with no return value. The compiler will warn, but may not error.
BUT, why on earth would you even consider this? What are you trying to achieve?
And what does the calling code look like? If it is int someVar = getNumber();
then the value of someVar is undefined (which is A Bad Thing).
It sounds to me like you want to return two pieces of information, one of which tells you if the other is valid.
Try something like
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
Simple solution:
boost::optional<int> getNumber( )
{
// May now return an int, or may return nothing.
}
Alternative of exceptions is return of status code:
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>
For float and double there is an alternative but not for int types.
#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
}
Be careful when using NaN. Each condition on val will be true.
Make it a requirement for the user to check first that the queue is not empty (provide means for that).
Then you can:
- not check anything and simply invoke undefined behavior (access underlying data as if it was there) - it's the user's fault
- check and throw exception
- assert (result is undefined with NDEBUG)
Checking and then invoking undefined behavior (returning an arbitrary value) is the worst thing to do. You get both the runtime overhead of the check and the caller is no wiser, as the result is still undefined.
You could throw a specified exception and catch it accordingly.
You could also return a class/struct with some magic conversion that is useful for your special need.
Real-life example: once I had actually to return two pieces of information in the same return value, a value to report if a window message had been completely processed and the value to be returned for it if the processing was already completed. So I packed everything up in a class like this:
//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;
};
};
This allowed me to do just return false;
in a function that returned a MessageReturnValue if the message had still to be processed, or to return TRUE/15/whatever;
if the message had been completely processed and I already had a return value. The caller, on its side, could simply do
LRESULT MyWndProc(/* blah blah blah */)
{
MessageReturnValue ret = MyFunction(/* blah blah blah */);
if(!ret)
{
/* process the message */
return /* something */;
}
else
return (LRESULT)ret;
}
If you have more complicated needs, you could also consider using boost::tuple.
In C++ a function must return a value (value type, reference, or address) if one is specified in the function declaration/definition.
You could throw an exception. You'd not return anything, but you'll have to catch the exception to determine what to do next (you could always swallow the exception and do nothing to achieve what you want).
A redesign of your method is likely in order if you need to break out of a function that's meant to return a value...or you could simply return an "error" value of some sort.
What is your actual use case?
If you really need to not return anything and terminate the normal function execution, you can throw an exception.
You can also return something that the caller interprets as an error (or 'nothing returned').
Whatever your solution is, the caller needs to handle the 'nothing returned' case separately, e.g. catch the exception or check the returned value.
You could use setjmp/longjmp (see http://en.wikipedia.org/wiki/Setjmp.h), but from a software engineering perspective you are better off using either exceptions or error codes as mentioned by others here.
精彩评论