is "return((void*)1)" safe?

Started by
47 comments, last by Nitage 14 years, 12 months ago
It is a pretty common convention to return a null pointer to indicate that a function failed. I would argue that this would be more intuitive than using something like -1 since many people automatically expect this behavior and check for null pointers. Knowing that one needs to check for -1 would require one to be up to date on documentation, and although checking documentation is important, a very good codeset will be as intuitive as possible from it's interface alone.
Advertisement
don't use some weird sentinel value. it's ugly and error prone.

Two possible solutions

1: Use an exception to indicate error (assuming this is C++ and not C).

2: Return an enum that clearly describes the state of the function and pass the data back as a either a result struct or a reference parameter i.e.
enum Result{   Success,   Failure,   SpecialCase}// and either struct ReturnValue{    void* data;    Result result;}}ReturnValue SomeFunc();// or Result SomeFunc(void** data){}


neither of those are very nice, so the exception is probably the way to go if you can do it that way.
if you think programming is like sex, you probably haven't done much of either.-------------- - capn_midnight
Using something like Optional<T> would let you know the value is invalid, but null pointers handle that anyway. If you need to interpret the result, I'd find another way. Perhaps another function to call which can retrieve the error value, or pass in an additional parameter to store the error code if you really need it. If you hate all these ideas, now you know why exceptions exist.

Try to keep your code logical: null pointers means invalid, anything else is valid. If I saw your function and tried to use it, that's exactly what I'd expect to be returned.
-- gekko
Quote:Original post by ChaosEngine
1: Use an exception to indicate error (assuming this is C++ and not C).

I would advise against that. Exceptions are not meant for indicating common errors. When an exception is thrown, it involves flushing the CPU pipeline, alerting the operating system, unwinding the stack, and returning to user code. In other words, it's exceptionally slow (pun intended) compared to just setting a flag.

Exceptions are for things that really haven't been anticipated. Stuff that is reason for shutting down the entire application or at least a module. Especially in game development the performance hit for frequent exception throwing is unacceptable.
Quote:2: Return an enum that clearly describes the state of the function and pass the data back as a either a result struct or a reference parameter i.e.

This is an excellent solution. And the syntax is really not that bad compared to try/catch blocks. Handling common errors simply isn't something you can tuck away so it has to be dealt with explicitely.

Anyway, it sounded to me like floatingwoods's function regularly hits the special case. Right? There might even be better solutions, like avoiding the special case early, or even avoiding it altogether, but then we need to know more about what exactly he's doing...

Anyway, there's another alternative: return a pointer to a static 'invalid' object that you can test against. This way you make sure that this pointer can never represent any other, valid object. But do document this really well so that people using this function know they should test for the invalid object before doing anything else.
Quote:Original post by C0D1F1ED
Anyway, there's another alternative: return a pointer to a static 'invalid' object that you can test against.

Isn't that essentially what ingramb suggested? Ah, but the object would have to be declared outside the function scope so calling code can access it. Yes, pretty messy.
[Window Detective] - Windows UI spy utility for programmers
Quote:Original post by floatingwoods
I have a function that returns a block of data depending on the arguments. Sometimes the functions doesn't return any data


You've already contradicted yourself. :)

Quote:in which case the return value is set to NULL. However other times I just want to signal a special case without returning any data nor changing the number of arguments of my function.


What's special about this case, besides the fact that it doesn't return any data?
Actually Zahlman you asked the right question.

My function is a function that is present in several extension modules (dlls) of my main application. The main application will broadcast a message to all modules. Each module can:

1) return NULL, in which case the broadcast continues
2) return data, in which case the broadcast is interrupted (other modules won't receive that message)
3) return "that special signal" indicating that the broadcast should be interrupted without having a return value

As many suggested, the problem can be solved in various ways without having the 3 distinct return values, but since I already have several extension modules, I was attempted to keep the old modules "as is", instead of rewriting the function (e.g. with different parameters). But I think being lazy never pays off in the long run...
So if you do want to rewrite your old modules, you should use boost::optional<T>. Seems to be the right place to use it.
Quote:Original post by owl
I've seen many libraries keep track of status/error codes from the last executed function.


Which isn't all that nice either imho, as it either requires you to use thread local storage, or it wouldn't be possible to use the code from different threads at the same time, even when it's working on completely independent data.
Quote:Original post by floatingwoods
Actually Zahlman you asked the right question.
He tends to do that...[lol]
"In order to understand recursion, you must first understand recursion."
My website dedicated to sorting algorithms

This topic is closed to new replies.

Advertisement