About using C++ exceptions

Discussion in 'Game Development (Technical)' started by derlogiker, Jun 8, 2007.

  1. Fabio

    Original Member

    Joined:
    Sep 30, 2005
    Messages:
    499
    Likes Received:
    0
    Your knowlegde of C++ appears to be so limited that to keep talking with you is only wasted time. Do your sterile polemics with someone else who has got free time to dedicate to you.
     
  2. Greg Miller

    Greg Miller New Member

    Joined:
    Feb 22, 2007
    Messages:
    27
    Likes Received:
    0
    The classic C-style "return/if" method is rather expensive on modern processors (branches in general are pretty expensive, as an incorrect guess by the CPU tends to result in the pipeline being flushed).

    How expensive exceptions are depends on the implementation method. The latest technique is to record the addresses of functions that have destructor calls to make separately from the actual code and look the functions up by their return addresses if an exception is thrown. That way, you don't execute any code at all for error-handling unless an error actually occurs. Error-handling is never going to get any more free than that.

    Of course, not every compiler and ABI uses this method. Off the top of my head, I couldn't tell you which ones do.
     
  3. MedievalElks

    MedievalElks New Member

    Joined:
    Jul 25, 2006
    Messages:
    82
    Likes Received:
    0
    I'm lacking in knowledge of C++ because I prefer polymophism to if-else blocks and RTTI? If you say so...
     
  4. Fabio

    Original Member

    Joined:
    Sep 30, 2005
    Messages:
    499
    Likes Received:
    0
    No, it's because you think that if-elseif-elseif-elseif-elseif-else-blocks and RTTI are there as an alternative to Polymorphism, which is plain senseless to think.
     
  5. MedievalElks

    MedievalElks New Member

    Joined:
    Jul 25, 2006
    Messages:
    82
    Likes Received:
    0
    Certainly not the only use of RTTI, but it's a common bad smell in C++ code. I've seen it in code for years. I'm not saying that I recommend the practice, in fact quite the opposite.
     
  6. bvanevery

    bvanevery New Member

    Joined:
    Jun 25, 2007
    Messages:
    369
    Likes Received:
    0
    Indeed. Most of these comments have been about performance. But, in my view, error checking rituals are a serious waste of time at various points in your development. Particularly at the prototyping stage. You may pretend you're going to throw and catch all these errors, or pass return values and implement graceful fallbacks for everything, but you won't. Probably your code will change 5 more times before your design stabilizes, and any mental masturbation you spent on error checking will prove thoroughly useless.

    Since I don't know what the error handling policy should be in advance, I just "log and warn." That way, I've made a note in the code that an error is possible, and that an error is happening, but I don't try to do anything about it. I don't pass errors around in hierarchies until I know there's a good reason for it. That's just passing the buck.
     
  7. GolfHacker

    GolfHacker Member

    Joined:
    Oct 4, 2006
    Messages:
    1,073
    Likes Received:
    0
    I never use exceptions. They're a pain. First problem: most coders don't know how to use exceptions properly (i.e., they throw exceptions more often than they should). They're supposed to be exceptional. I've seen people throw exceptions from functions just so they can send back an error message or state information along with the return result. I've seen people throw them to terminate a loop. Those are bad designs. Second problem: if there's no catch to catch the exception, your program dies - this is far worse than just returning an error code and having the caller ignore it. Third problem: it can be confusing to follow the flow of logic or to debug because of the way you leap around the program when a exception is thrown - with a lot of debuggers, you can't even tell where the exception was thrown FROM. Visual Studio at least lets you break when an exception occurs, but not all debuggers provide this option.

    Here's some additional information about performance with exceptions from the book, "More Effective C++" by Scott Meyers - a book EVERY C++ programmer should read and have on their shelf:

    1. Exception handling has costs, even if you never use the keywords "try", "throw", or "catch". You pay for the space used by data structures to keep track of which objects are full constructed, you pay for the time needed to keep these data structures up to date. These costs are modest, but programs compiled without support for exceptions are typically faster and smaller than those that do have exception support built in.

    2. You pay whenever you use a try block (i.e., whenever you decide you want to be able to catch exceptions). The cost varies from compiler to compiler, but in general your code size will increase 5-10% and your performance will decrease by about the same amount. This cost comes from just having the try block, and does not include catching anything.

    3. Throwing an exception is the most costly, obviously. This typically shouldn't be a concern because exceptions should be rare (unless you're one of those bad coders who use exceptions when you're not supposed to). Compared to a normal function return, returning from a function by throwing an exception may be as much as three orders of magnitude slower, according to the benchmarks that Scott Meyers references. That's a big hit. But you only take the hit if you actually throw an exception, which should be never.

    As GBGames said earlier, most casual and indie games probably don't need to be too concerned. It's only if you're doing some seriously intense real-time rendering that you need to worry. To minimize the performance overhead, compile without support for exceptions whenever possible, limit your use of try blocks to those locations where you really need them, and throw exceptions only under conditions that are truly exceptional.
     
  8. Bad Sector

    Original Member

    Joined:
    May 28, 2005
    Messages:
    2,742
    Likes Received:
    5
    Exceptions are a hack for C++'s (and most other OOP-enabled languages) inability to make a constructor return NULL :p.

    Ok, they're more than that, but i believe that it's very rare to really need them (which somehow justifies their name).

    But i would love to have a C++ constructor return NULL :). Why do
    Code:
    Foo bar = new Foo();
    if (!bar.init("lala.dat"))
    {
            delete bar;
            return 0;
    }
    
    when you can simply do
    Code:
    Foo bar = new Foo("lala.dat");
    if (!bar) return 0;
    
    I don't see any reason on why a constructor cannot do something fail-able. After all it constructs the object and it's construction can fail.
     
  9. Backov

    Original Member

    Joined:
    Oct 23, 2005
    Messages:
    812
    Likes Received:
    0
    Because having a constructor fail is an exceptional occurrence and shouldn't need to be checked.
     
  10. Bad Sector

    Original Member

    Joined:
    May 28, 2005
    Messages:
    2,742
    Likes Received:
    5
    Why is an exceptional occurence?

    If i have an Image class that loads an image file from it's constructor it's plain normal to want to return NULL from the constructor if the image loading fails. Or when i allocate memory for an empty image, the allocation may fail. This is stuff that, for convenience, i would like to put in constructors. However C++ doesn't provide me with a clean mechanism to do that (i can do it using exception - pretty much the same how Java uses their exceptions - but i don't consider this mechanism "clear"... a "return NULL" would be more appropriate IMHO).

    Of course, i could use creation functions, like newImage or createImage, etc which can return NULL (and that's what i'm doing usually) but this is doing more work for something that could be solved if the language had this little feature.
     
  11. Fabio

    Original Member

    Joined:
    Sep 30, 2005
    Messages:
    499
    Likes Received:
    0
    What about static objects? How would the language handle a failed constructor in that case?

    As you see C++ is so full of features and possibilities that some apparently obvious things cannot be implemented because they would break something else.

    C++ is far from being perfect, but it's still probably the most powerful and productive system language out there, and to a big extent not only "system".
     
  12. Bad Sector

    Original Member

    Joined:
    May 28, 2005
    Messages:
    2,742
    Likes Received:
    5
    I thought about that. I didn't meant that "return NULL" should be the real method. It could be something else. Something that simply invalidates the object.

    Or it could just not allow static objects when the return statement is used in constructors.

    I disagree. C++ is just more popular because it is an extension and most compatible with C, which *is* a very good language. C++ is just a monster and some features are plain uglyness (dynamic_cast<bleh>(omg) anyone?). Unfortunately it's also the only "C extension" that can use C code almost as-is and provide object oriented features.

    Anyway, this discussion has no point. C++ doesn't have this thing..

    (of course i can always hack into g++'s source and add it myself, but that doesn't mean that it'll be added in the official g++)
     
  13. GolfHacker

    GolfHacker Member

    Joined:
    Oct 4, 2006
    Messages:
    1,073
    Likes Received:
    0
    I think maybe you're doing too much work in your constructor. A constructor should be as compact as possible in order to reduce overhead and minimize errors. The constructor is called every time an object is created - this often occurs without your control, such as when the compiler creates temporaries. Only do what is minimally necessary during construction, and especially in a default constructor.

    Another thing to consider: if you throw an exception from a constructor, the object's destructor is NOT run. This results in a memory leak.

    One alternative is to use a smart pointer, like std::auto_ptr. The smart pointer will automatically delete the object when the smart pointer dies, even if there was a problem during instantiation.

    Another alternative is to use your constructor to only initialize class members to default values (pointers to null, etc), then have a separate initialize method to perform the bulk of the real initialization. To save your callers the extra line of code, you can implement a factory pattern or perhaps a static creation method that does the work like this:

    MyClass*
    MyClass::instance()
    {
    MyClass* myobject = new MyClass();
    myobject->initialize();
    return myobject;
    }

    You can put any kind of error handling you want in here, your initialize method can return error codes, or whatever.
     
  14. lennard

    Moderator Original Member Indie Author

    Joined:
    Jan 12, 2006
    Messages:
    2,390
    Likes Received:
    12
    Interesting discussion for a Monday morning. Off for a constitutional to think about my strategy of write quickly, tossing out the bits that aren't fun as I go along - I think mostly I need to get back into the habit of cleaning up (should that be refactoring?) my code as my projects progress. I would generally agree with Applewood that once something in the game fails then you are hooped as my games aren't written to be fault tolerant, they are meant to be bug free when they ship. That said, having some kind of function (I use Exit with a variable length list of parameters) to report back why the game got screwed can at least give you a starting point (and a log is better).

    Anyhow, got a chuckle out of the "sterile polemics" line. Sounds like baffle 'em with bullshit or, I'm clearly so much smarter than you are that you shouldn't even try to argue with me. Lighten up dude.
     
  15. Fabio

    Original Member

    Joined:
    Sep 30, 2005
    Messages:
    499
    Likes Received:
    0
    But a lot of code can still be written to directly access the static object. Should the language be defined so that the code that refers to those objects gets automatically deleted? Only the statements or the whole functions?

    One of the most sucky things in a language is the lack of orthogonality. Learning thousands rules and millions crossed exceptions to those rules (Intel anyone?).

    As you see there's no way you can do it in a coherent way with static objects (which HAVE their use, also for performance reason), not without introducing eventually a lot of virtualization and thus overhead.

    Your solution may work but will only add confusion to an already very confused language.

    Don't forget that C++ wasn't only meant to be an extension of C, but someway the "definitive" language. I don't think they* succeeded, anyway. ( *they because it's not only Bjarne, you know. Just like Linux is not only Linus.. )

    I think the same.. but that doesn't mean that you've to take the whole C++ monster or nothing. C++ offers a lot of stuff, it's up to you to know what can be useful to your application and what can be overkill. Remember that some are there just to please the whole committee.

    Perhaps you can, but not with static objects anyhow. ;)
     
  16. Fabio

    Original Member

    Joined:
    Sep 30, 2005
    Messages:
    499
    Likes Received:
    0
    Got that one too when I've read "why would you use RTTI when you should be using polymorphism instead? Write in plain C if you're going to use C++ that way." [emphasis mine]

    Anyway, when A and B discuss with each other, even publicly, C (and C++) should avoid to enter into these discussions IMHO.

    Also, not everyone here is a native English speaker, so lighten up.
     
  17. Bad Sector

    Original Member

    Joined:
    May 28, 2005
    Messages:
    2,742
    Likes Received:
    5
    @GolfHacker:
    I don't really use many static objects. In fact i only use "simple utility objects" as static objects (like vectors, matrices, etc). Most of "big" objects are dynamic objects which i manually allocate. So i don't have problems with accidental object creation.

    Also i don't really like "smart pointers" :p.

    Anyway, i don't really do stuff that might fail in a constructor. As i said in my previous post, most of the fail-able stuff is done in a special "init" function or in a createFoo function. I just wish i didn't had to do this wrapping manually.

    @Fabio:
    Since when C++ is orthogonal? And even if it was, i really prefer to have an additional feature that will save me some code and add a little extra rule instead of not having that feature at all.

    Anyway, i admit that i didn't thought about this much, so it's natural to have issues.

    On the other hand, it's probably a nice feature to add in UndeadScript, since all objects there are dynamically created ;-)
     
  18. MedievalElks

    MedievalElks New Member

    Joined:
    Jul 25, 2006
    Messages:
    82
    Likes Received:
    0
    For what are you using dynamic_cast? That's usually a sign of bad design.
     
  19. Bad Sector

    Original Member

    Joined:
    May 28, 2005
    Messages:
    2,742
    Likes Received:
    5
    First of all, i completely disagree with those "if you use <feature X> then that's a sign of bad design" responses. Sorry, but to me language features (and even design methodologies) are to be used. Using a feature is not the same as abusing it.

    Secondly, i never used the "dynamic_cast" feature. For years now, C-like typecasting is all i needed. In fact, i'm not even sure what's the difference between C's typecasting and dynamic_cast, static_cast or whatever else C++ has.

    Third, i mentioned "dynamic_cast" as an example of ugly (according to my taste, at least) C++ syntax. I could mention other stuff instead (like templates).
     
  20. MedievalElks

    MedievalElks New Member

    Joined:
    Jul 25, 2006
    Messages:
    82
    Likes Received:
    0
    That's why I qualified it with "usually".
     

Share This Page

  • About Indie Gamer

    When the original Dexterity Forums closed in 2004, Indie Gamer was born and a diverse community has grown out of a passion for creating great games. Here you will find over 10 years of in-depth discussion on game design, the business of game development, and marketing/sales. Indie Gamer also provides a friendly place to meet up with other Developers, Artists, Composers and Writers.
  • Buy us a beer!

    Indie Gamer is delicately held together by a single poor bastard who thankfully gets help from various community volunteers. If you frequent this site or have found value in something you've learned here, help keep the site running by donating a few dollars (for beer of course)!

    Sure, I'll Buy You a Beer