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

Started by
47 comments, last by Nitage 14 years, 11 months ago
Quote:Original post by C0D1F1ED
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.
I'm afraid neither of that is quite true. Exceptions are a means to recover from errors in a graceful manner without killing the process. Killing the process or shutting down a module is not error handling, it is failure.
If you use exceptions only to kill the process, you can as well use assert(), it has easier syntax, and less overhead (but again, this is failure, not error handling).

The performance hit for exceptions is not at all unacceptable, unless you throw maybe 20,000 times per second. While it is true that exceptions are relatively expensive, they also are exceptional, they don't occur that often.
Even a hundred exceptions per second are not noticeable at all, and your code likely won't throw that many (or you have other problems!).
Advertisement
Quote:Original post by SiS-Shadowman
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.


QFE. I use it a lot. Together with tuple<> it helps me to write 99.9% of my functions in The Right Form "Function (input) -> output".
boost::optional really isn't much of an improvement here. A pointer already has a value that indicates a missing value: null. Adding boost::optional to the mix means that you'll have two different representations for a missing value. This is hardly what you would call self-documenting code.
Quote:Original post by quasar3d
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.


Well, at least it is cleaner than mixing return codes with unrelated return value types. Having it working in a per thread basis is the right way to do it thread safe. If you wanted to get different error codes from a function without changing it's interface, I really can't think of any other way to do it.
[size="2"]I like the Walrus best.
The only reasonable numbers are zero, one, and infinity.

Your function returns two types of values: blocks of data and status.

Two is not a reasonable number.

You design is unreasonable.

You ask if it is reasonable to do something outside of accepted practise in order to salvage your unreasonable design. Unfortunately, unreasonability is commutative and distributive. The answer is that it is not reasonable to return (void*)1 in this case.

See, programming is a process of reasoning about the current and future state of a complex mathematical function. You cannot, by definition, reason about something unreasonable.

So, the solution is that you should change your design. If you would like a suggestion, return your data by parameter and your status by value (following the classic C idiom).

Stephen M. Webb
Professional Free Software Developer

Quote:Original post by SiCrane
boost::optional really isn't much of an improvement here. A pointer already has a value that indicates a missing value: null. Adding boost::optional to the mix means that you'll have two different representations for a missing value. This is hardly what you would call self-documenting code.


I am not sure. The original post said:

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


So, what I read from this, he has three cases:

  • return dataset
  • return empty dataset (indicated by null)
  • return nothing


In two of three cases, the pointer is of interest. In the last one, it is of more interest to determine that there is no data (i.e. return value) at all, for what I think optional<> is exactly for.


edit:typo


edit:

On the other hand, if he doesn't want to return nothing, but rather (ErrorCode xor Data), then something else than optional<> is required. A clean but still kissy approach that comes to my mind atm would be to use a tuple with a signature ca. like "tuple<status,data>".

Even more clean, but not so kiss conformant anymore would be "tuple<optional<status>,optional<data>>", as there is no status necessarily returned, and also no data is necessarily returned. Somehow, that's still not clean enough, as (ErrorCode xor Data) can't be modeled. Or just make status an own type which defaults to "okay".

Anyways, for the tuple of optionals, I think I take my hat and run. My grandma would kill me if I told her that.

[Edited by - phresnel on April 22, 2009 8:12:36 AM]
Maybe I'm missing something, but couldn't you change the function to return an object or a struct for a response, instead of returning a void*?

struct Response{    bool inturrupt;    void* data;}

Change the signature to always return the "Response" struct. That way you can return data or not, and you also have a bool for this special case where you need to inturrupt the broadcast.

Edit: My apologies to ChaosEngine, who actually suggested pretty much the same thing, on the previous page.

[Edited by - BTownTKD on April 22, 2009 9:00:24 AM]
Deep Blue Wave - Brian's Dev Blog.
Personally I'd say the struct return, or returning the pointer as an out parameter, would be most reasonable. Win32 would take the latter approach.
SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.
In case you have multiple "non data signals", I also recommend the struct. If you only have "either data or invalid", I'd go with optional<>.

But anyways, I felt the urge (for fun) to hack together a class that represents either a type A, xor a type B. Not for production use, could need some more engineering (better not use with pointer types):

XorType
#include <iostream>#include <stdexcept>template<typename TL, typename TR> struct types_equal { enum { value = 0 }; };template<typename T> struct types_equal<T,T> { enum { value = 1 }; };template<typename TL, typename TR>class XorType {        // Mutable to allow for move semantics. Otherwise we would have        // to let the copy-constructor accept an non-const reference, which        // would then yield ambiguous constructor calls in rest of code.        mutable std::auto_ptr<TL> tl;        mutable std::auto_ptr<TR> tr;        // Forbid standard construction.        XorType () ;        // Forbid copy assignment.        XorType & operator= (XorType<TL,TR> &rhs)public:        XorType (TL const &tl_) : tl(new TL(tl_)), tr(0) {}        XorType (TR const &tr_) : tl(0), tr(new TR(tr_)) {}        XorType (XorType const &tt) : tl(tt.tl), tr(tt.tr) {}        // These can currently yield unwanted effects if something else then        // TL or TR is requested.        operator TL () const {                if (0 == tl.get()) throw std::exception ();                return *tl;        }        operator TR () const {                if (0 == tr.get()) throw std::exception ();                return *tr;        }        // More safe.        TL getL () const {                if (0 == tl.get()) throw std::exception ();                return *tl;        }        TR getR () const {                if (0 == tr.get()) throw std::exception ();                return *tr;        }        // Checks if this is of type T.        template <typename T> bool is () const {                if (types_equal<T,TL>::value && (0!=tl.get()))                        return true;                if (types_equal<T,TR>::value && (0!=tr.get()))                        return true;                return false;        }        // More safe versions.        bool is_ltype () const {  return is<TL>();  }        bool is_rtype () const {  return is<TR>();  }};


Usage Example
enum ErrorCode {        FileNotFound = 0xBEEF        // etc.};XorType<ErrorCode, float> foo () {        return 5.5f;}XorType<ErrorCode, float> bar () {        return FileNotFound;}


main()
int main () {        {                XorType<ErrorCode, float> hmm = foo();                // using template variant                if (hmm.is<ErrorCode>())  std::cout << (ErrorCode)hmm << '\n';                else if (hmm.is<float>()) std::cout << (float)hmm << '\n';        }        {                XorType<ErrorCode, float> hmm = bar();                // using other variant                if (hmm.is_ltype())       std::cout << (ErrorCode)hmm << '\n';                else if (hmm.is_rtype())  std::cout << (float)hmm << '\n';        }        // provoke an error        std::cout << "===================================================="                  << "\nIn case you copypasted this code without skimming\n"                  << "through it, it will now intentionally throw.\n"                  << "====================================================\n\n"                  << std::flush;        try {                XorType<int,float> hmm(6);                (float)hmm;        } catch (...) {                std::cout << "Caught Exception. Read above comment.\n";        }}
looks funky, but allocating memory on the heap, just to return a simple float?

This topic is closed to new replies.

Advertisement