Sign in to follow this  

Unity [C++] Exceptions using them right

This topic is 2792 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

EDIT: seems like some questions below are answered here as well: http://www.gamedev.net/community/forums/topic.asp?topic_id=569089 I'm fairly new with exceptions, I don't use them much myself but I'd like some advice :) 1. Is it generally a good idea to put a throw specifier in a function definition? Like: void f() throw(std::bad_alloc); void f() {} 2. I guess it is, does it also make sense to set the throw specifier for functions that do not throw anything? 3. What to do when in debug build there's more throws then in release mode? Or is this a malformed design? Like when a function does throw in debug mode, but doesn't in release mode. How would you define the function prototype? Dependent on whether its debug/release? 4. Should I catch memory / third-party-library exceptions, handle them correctly and re-throw it? Or catch them and then throw my own exception class instead? 5. There's a difference between logging, warnings, fixable errors (like, when input is incorrect it could take a default sometimes) or regular errors. Which are best to be thrown? For debug? For release? Where do you make a distinction, or do you also use a second method for error reporting then exceptions? I generally feel like exceptions produce quite a bit of bloat in the executable. Of course, for debug mode this is no problem. In debug mode we want to debug and thus good error reporting. In release I suppose only critical errors are relevant... Thanks for the input!

Share this post


Link to post
Share on other sites
Quote:
Original post by Decrius
I'm fairly new with exceptions, I don't use them much myself but I'd like some advice :)
Use exceptions only in exceptional circumstances.
Quote:

1. Is it generally a good idea to put a throw specifier in a function definition? Like: void f() throw(std::bad_alloc); void f() {}
No. Avoid using throw specifiers in C++. They do not do what you think they do. They are a deprecated language feature. Do not use them.
Quote:

2. I guess it is, does it also make sense to set the throw specifier for functions that do not throw anything?
No, not at all.
Quote:

3. What to do when in debug build there's more throws then in release mode? Or is this a malformed design? Like when a function does throw in debug mode, but doesn't in release mode. How would you define the function prototype? Dependent on whether its debug/release?
This should not occur. Either you can handle an exception or you can't.
Quote:

4. Should I catch memory / third-party-library exceptions, handle them correctly and re-throw it? Or catch them and then throw my own exception class instead?
If you can't handle an exception, ignore it and let someone else handle it. That's the point of exceptions. If you can handle it, don't rethrow it, it's been handled.
Quote:

5. There's a difference between logging, warnings, fixable errors (like, when input is incorrect it could take a default sometimes) or regular errors. Which are best to be thrown? For debug? For release? Where do you make a distinction, or do you also use a second method for error reporting then exceptions?
Use exceptions only for exceptional circumstances. Input errors are not exceptional, they are expected.
Quote:

I generally feel like exceptions produce quite a bit of bloat in the executable.

Feelings should have little to do with it. Exceptions do not add bloat and they do not affect the nonexceptional execution path in any meaningful way. Applications that use exceptions correctly tend to be larger than those that do not handle errors at all, which is the usual comparison.

Do not confuse C++ with Java exceptions. Java exceptions are more akin to the C method of passing status values ads return values. They are two different paradigms.

Share this post


Link to post
Share on other sites
Quote:
Original post by Decrius

1. Is it generally a good idea to put a throw specifier in a function definition? Like: void f() throw(std::bad_alloc); void f() {}

2. I guess it is, does it also make sense to set the throw specifier for functions that do not throw anything?
No. These specifiers have always been somewhat problematic for no benefit.

Quote:
3. What to do when in debug build there's more throws then in release mode? Or is this a malformed design?
Yes. Interfaces should be consistent. There is no "debug mode" in C++, it's just a preselected set of compiler switches - application doesn't change.

Quote:
4. Should I catch memory / third-party-library exceptions, handle them correctly and re-throw it? Or catch them and then throw my own exception class instead?
It doesn't matter who throws it. If an exception can be handled, and cause of exception fixed, then code should do so when it can, otherwise pass the exception to propagate upwards.

Quote:
5. There's a difference between logging, warnings, fixable errors (like, when input is incorrect it could take a default sometimes) or regular errors. Which are best to be thrown?
Those that are exceptions.


Quote:
I generally feel like exceptions produce quite a bit of bloat in the executable.
Yes. If only we had more than 1TB drives and more than 4GB of RAM.

Quote:
In debug mode we want to debug and thus good error reporting. In release I suppose only critical errors are relevant...
This has nothing to do with exceptions. They are not error reporting tool, they are flow control. In some cases, an exception will be handled by logging the exception message.

And exceptions are not logs. They don't have different levels of severity. When an exception is throw, it indicates that catastrophic error has occurred, so bad, that there was simply no possible way for code to continue executing.

Share this post


Link to post
Share on other sites
Quote:
Original post by Bregma
Quote:

3. What to do when in debug build there's more throws then in release mode? Or is this a malformed design? Like when a function does throw in debug mode, but doesn't in release mode. How would you define the function prototype? Dependent on whether its debug/release?

This should not occur. Either you can handle an exception or you can't.


Should not occur as in: there shouldn't be a difference between debug/release mode in what is thrown (this can make sense if it's only used for exceptional cases)? Or as in the function prototype definition, which is a non-issue when not using throw()-specifiers (which I don't plan to implement, after reading your and others their advice).

EDIT: Antheus clarified this: no difference between debug / release.

Quote:
Original post by Bregma
Quote:

5. There's a difference between logging, warnings, fixable errors (like, when input is incorrect it could take a default sometimes) or regular errors. Which are best to be thrown? For debug? For release? Where do you make a distinction, or do you also use a second method for error reporting then exceptions?

Use exceptions only for exceptional circumstances. Input errors are not exceptional, they are expected.


Sounds good. How would you handle expected errors then? What if someone passes raw pixels + width + height to a function, and for some reason the width / height is zero. How would you inform the caller that the input is wrong?

Quote:
Original post by Antheus
And exceptions are not logs. They don't have different levels of severity. When an exception is throw, it indicates that catastrophic error has occurred, so bad, that there was simply no possible way for code to continue executing.


I see, I used it way too much then all the time.

Thanks both.

Share this post


Link to post
Share on other sites
Quote:
What to do when in debug build there's more throws then in release mode? Or is this a malformed design? Like when a function does throw in debug mode, but doesn't in release mode. How would you define the function prototype?
I only do this in code that is designed to not use exceptions at all -- I still use them in debug builds for assertion failures, which usually get thrown all the way back to main (or to a unit test handler).
It could be a hint of a malformed design...
It shouldn't affect the prototype though, because as mentioned in other posts, exception specifiers aren't a good idea anyway.
Quote:
5. There's a difference between logging, warnings, fixable errors (like, when input is incorrect it could take a default sometimes) or regular errors. Which are best to be thrown?
Logging, warnings and fixable errors definitely aren't good cases for exceptions. Errors that stop you from continuing are a maybe. In a game, there's not that many cases that should stop you from continuing though -- you should try to make as many of your errors "fixable" or "tolerable" as possible.
Quote:
Exceptions do not add bloat and they do not affect the nonexceptional execution path in any meaningful way. Applications that use exceptions correctly tend to be larger than those that do not handle errors at all, which is the usual comparison.
Unfortunately enabling exceptions does generate extra code - for all the stack-unwinding that wouldn't otherwise need to be there.
This isn't usually a problem (especially on the PC), but if you're targeting hardware with a tiny cache (or you have other space restrictions), then this can actually be a problem and you might want manual control of where the exit points of a function are instead of having the compiler insert them all over the place.
e.g. The Wii has 0.25MB of L2 Cache, the 360 has 2MB and some Core 2 Duos have 6MB. So, yeah, on your PC - probably not a problem.
Quote:
Original post by Decrius
How would you handle expected errors then? What if someone passes raw pixels + width + height to a function, and for some reason the width / height is zero. How would you inform the caller that the input is wrong?
If that situation can occur from someone feeding bad data into your program, then you should probably just return an error code (e.g. "This function will return NULL if the parameters fail the pre-conditions"), and then have the calling code check for failure (and perhaps log the error and continue).

Share this post


Link to post
Share on other sites
In addition to the memory issues, it's worth mentioning that most console platforms simply don't allow you to use exceptions, period. The vendors either strongly suggest you don't (because the compilers aren't optimized to deal with them), or they ship compilers that don't support them at all.

Share this post


Link to post
Share on other sites
Quote:
Original post by Decrius
4. Should I catch memory / third-party-library exceptions, handle them correctly and re-throw it? Or catch them and then throw my own exception class instead?


Just to add some extra stuff to this one.

Exceptions are part of an interface, even if throw specifiers aren't present (and it's generally accepted that they shouldn't be as others have noted). So it can be a good idea to document the exceptions that can be thrown by various parts of your code, even if it's just to say "all standard library and foolib exceptions may be thrown by this function".

So if you're creating a library or subsystem that uses another library internally, you might consider catching all exceptions thrown by that inner library and converting them to your own class(es) of exception.

If you don't do this, then you're exposing an implementation detail of your subsystem. Often this exposure isn't a big deal, but it's something to keep in mind if your writing what you hope will be a long-standing interface.

For example, if you write a class use the Xerces XML library to read a Collada file, should the user expect to have to catch exceptions defined by Xerces? Perhaps you'll change your XML library to RapidXML or something in future...

But in general, you should only catch exceptions if you can handle them in a useful way, or if you need to release resources in the case of an exception being thrown e.g.


thing *tp = new thing(x,y,z);

try
{
something_that_may_thrown();
}
catch (...)
{
delete tp;
throw;
}


A dumb example, but this is probably one of the few valid uses for "catch(...)", IMO. However, if you find yourself writing code like this, you could and probably should re-cast your code in such a way as to use RAII:


thing t(x,y,z); // morally equivalent to all of the above!


EDIT: and one final point on this. If you expect to be able to recover meaningfully from exceptions at various points in your application, you should make sure you write your code in an exception-safe way. This takes practice, patience and discipline but the code one ends up with is often much cleaner (anecdotally).

The RAII mechanism of C++ actually makes this a lot easier to do than in many other languages as you don't need IDisposable/using (C#), "with" statements (Python), or boilerplate "finally" blocks (many others). Though RAII won't solve all possible exception safety issues, it will at least prevent leaks.

Share this post


Link to post
Share on other sites
Thanks the_edd. It sounds consistent to re-throw my own exception yeah. I also thought of a comment behind the prototype to document which exception might occur, good idea!

Also, for validating user / programmer input to a function; an alternative to Hodgman's return code method, would it be a good idea to do an assert on user input?

I read that asserts should be used for expressions that are always true to your believes (but sometimes turn out to be false -> useful debug information). How well would it be to use asserts for user-input validation?

Share this post


Link to post
Share on other sites
Quote:
Original post by Decrius
Also, for validating user / programmer input to a function; an alternative to Hodgman's return code method, would it be a good idea to do an assert on user input?

IMO, it would be a bad idea.

Quote:

I read that asserts should be used for expressions that are always true to your believes (but sometimes turn out to be false -> useful debug information).

Yes.

Quote:

How well would it be to use asserts for user-input validation?


Not well at all. Rule of thumb: asserts are for implementers, exceptions are for clients.

If an assert fails, your program will be aborted, it will not pass Go, it will not collect £200. On unexpected/inadequate user input, you presumably don't want that to happen. Instead return an error code or throw an exception and when the time is right, display a useful error message.

And of course, the assert macro provided with the C and C++ standard library is effectively removed at the pre-processing stage when the NDEBUG macro is defined.

Aside: some people create their own assert macros that allow execution to continue after reporting an error. Personally, I don't like that idea as it doesn't gel with the original idea behind an assertion. I would call such a macro "hope" rather than "assert".

Share this post


Link to post
Share on other sites
Quote:
Original post by Decrius
Thanks the_edd. It sounds consistent to re-throw my own exception yeah. I also thought of a comment behind the prototype to document which exception might occur, good idea!

There are a lot of problems with coding Java in C++. Java does not allow you to pass function pointers. Java requires throw specifications. C++ allows function pointers and does not implement Java-style throw specifications. As long as you write simple code, you can catch all contained exceotions and rethrow your own, but if you're providing any sort of customizable code (callbacks, delegates) you can not guarantee what code you call can throw. That means you're going to have to catch(...) and throw some sort of generic exception, just so you can act like Java.

If you never write code for others to extend, this is not a concern.
Quote:
Also, for validating user / programmer input to a function; an alternative to Hodgman's return code method, would it be a good idea to do an assert on user input?

I read that asserts should be used for expressions that are always true to your believes (but sometimes turn out to be false -> useful debug information). How well would it be to use asserts for user-input validation?

I have dealt with widely-available libraries (eg. OpenLDAP) that throw asserts in production code. I have cursed the authors of such code and their descendants to the seventh generation to eternal damnation in an inner circle of hell. Do not repeat their mistakes.

Share this post


Link to post
Share on other sites
Quote:
Original post by the_edd
Not well at all. Rule of thumb: asserts are for implementers, exceptions are for clients.


Sorry, I should have been more clear. It looks like I meant program-user input, but since I write a library, the user is actually the library-user and thus the program-programmer.

But yeah, I agree. Program-user input is something you almost know for sure is wrong and thus not assert-material.

So to rewrite my question: how well can asserts be used to document function arguments (assert whether the argument is valid) called internally in the library or externally by the programmer (the library-user)?
Currently I'm throwing exceptions, but this is not really exceptional. Neither a return-type is always possible (some objects just don't have a NULL-state).

Quote:
Original post by Bregma
I have dealt with widely-available libraries (eg. OpenLDAP) that throw asserts in production code. I have cursed the authors of such code and their descendants to the seventh generation to eternal damnation in an inner circle of hell. Do not repeat their mistakes.


Hehe, that's a hell of a curse ;). Why was this such a problem? There shouldn't be any asserts in release-mode, and in debug mode it should give useful debug information. How did they abuse the asserts so badly?

Thanks for the answers guys, helps me constructing and verifying my thoughts ;)...eventually I might become a good programmer ^_^

Share this post


Link to post
Share on other sites
Quote:
Original post by Decrius
So to rewrite my question: how well can asserts be used to document function arguments (assert whether the argument is valid) called internally in the library or externally by the programmer (the library-user)?


I think that's fine. If you do use asserts in this way, just make sure to document the inputs that your function considers to be illegal.

If I see documentation that mentions a precondition for a library I'm using, I'll often add my own asserts before calling that function.

Ideally, you should use the type system as far as is practical to restrict the arguments to valid values. For example, if a pointer must be non-null, then you might change the argument to a reference instead.

Share this post


Link to post
Share on other sites
Quote:
Original post by the_edd
Quote:
Original post by Decrius
So to rewrite my question: how well can asserts be used to document function arguments (assert whether the argument is valid) called internally in the library or externally by the programmer (the library-user)?


I think that's fine. If you do use asserts in this way, just make sure to document the inputs that your function considers to be illegal.

If I see documentation that mentions a precondition for a library I'm using, I'll often add my own asserts before calling that function.

Ideally, you should use the type system as far as is practical to restrict the arguments to valid values. For example, if a pointer must be non-null, then you might change the argument to a reference instead.


Thanks the_edd for the useful info :D, this will get me to finish v1 hehe

Share this post


Link to post
Share on other sites
Quote:
Original post by Decrius
I'm fairly new with exceptions, I don't use them much myself but I'd like some advice :)


Read this.

Quote:
1. Is it generally a good idea to put a throw specifier in a function definition? Like: void f() throw(std::bad_alloc); void f() {}

2. I guess it is, does it also make sense to set the throw specifier for functions that do not throw anything?


No and no. C++ throw-specifications are damn near useless.

Quote:
3. What to do when in debug build there's more throws then in release mode? Or is this a malformed design? Like when a function does throw in debug mode, but doesn't in release mode. How would you define the function prototype? Dependent on whether its debug/release?


N/A because of the above.

Quote:
4. Should I catch memory / third-party-library exceptions, handle them correctly and re-throw it? Or catch them and then throw my own exception class instead?


If you've properly handled the exception, why would you need to re-throw anything? That said, there are plenty of reasons why you might want to catch an exception and throw an instance of your own back instead of the one you received. This is in order to "translate" the exception, and you'd do so for basically the same reasons you'd translate anything else.

Quote:
5. There's a difference between logging, warnings, fixable errors (like, when input is incorrect it could take a default sometimes) or regular errors. Which are best to be thrown? For debug? For release? Where do you make a distinction, or do you also use a second method for error reporting then exceptions?


Logging has nothing to do with exceptions. I don't know what you mean by "warnings". Otherwise, figuring what's "exceptional" is kind of an art form. Sorry.

Quote:
I generally feel like exceptions produce quite a bit of bloat in the executable. Of course, for debug mode this is no problem. In debug mode we want to debug and thus good error reporting. In release I suppose only critical errors are relevant...


This should not be a concern. The only time you would use exceptions in debug that aren't in release is where it helps you debug; but C++ doesn't expect you to use exceptions as a debugging tool (since there is static, manifest typing) but instead to handle things that couldn't be expected by the program (e.g. a missing file, insufficient memory).

Share this post


Link to post
Share on other sites

This topic is 2792 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this  

  • Forum Statistics

    • Total Topics
      628732
    • Total Posts
      2984436
  • Similar Content

    • By INTwindwolf
      THE PROJECT

      INT is a 3D Sci-fi RPG with a strong emphasis on story, role playing, and innovative RPG features such as randomized companions. The focus is on the journey through a war-torn world with fast-paced combat against hordes of enemies. The player must accomplish quests like a traditional RPG, complete objectives, and meet lively crew members who will aid in the player's survival. Throughout the game you can side and complete missions through criminal cartels, and the two major combatants, the UCE and ACP, of the Interstellar Civil War.
      Please note that all of our current positions are remote work. You will not be required to travel.
      Talent Needed
       
      Unity Engine Programmer
      Website Administrator
      3D Animator
      We have made great strides in the year 2017! INT has received a comprehensive face-lift compared to the start of the year. We look forward to a productive, fruitful year 2018!
      Revenue-Share
      This is the perfect opportunity to get into the game development industry. Being an Indie team we do not have the creative restrictions often imposed by publishers or other third parties. We are extremely conscientious of our work and continuously uphold a high level of quality throughout our project.
      We are unable to offer wages or per-item payments at this time. However revenue-sharing from crowd-funding is offered to team members who contribute 15-20 hours per week to company projects, as well as maintain constant communication and adhere to deadlines. Currently the crowd-funding campaign is scheduled for the year 2018. Your understanding is dearly appreciated.
       
      Thank you for your time! We look forward to hearing from you!
       
      John Shen
      HR Lead
      Starboard Games LLC
    • By Apollo Cabrera
      Energy particles being harnessed by collection multi-hedron energy matrix. Whuuuttt?
      Love it :)
    • By AndySv
        Total Music Collection (http://u3d.as/Pxo)   THE COLLECTION CONTAINS:   Mega Game Music Collection   Universal Music Collection   Huge library of high quality music for any project! All at an incredibly low price!   - 2,5GB of high quality audio - 100+ different music tracks - Loop and short versions   Action, fantasy, casual, horror, puzzle, epic, dramatic, romantic, positive, inspiring, motivational and more!
    • By Dafu
      FES Retro Game Framework is now available on the Unity Asset Store for your kind consideration!
      FES was born when I set out to start a retro pixel game project. I was looking around for an engine to try next. I tried a number of things, from GameMaker, to Fantasy Consoles, to MonoGame and Godot and then ended up back at Unity. Unity is just unbeatable in it's cross-platform support, and ease of deployment, but it sure as heck gets in the way of proper retro pixel games!
      So I poured over the Unity pipeline and found the lowest levels I could tie into and bring up a new retro game engine inside of Unity, but with a completely different source-code-only, classic game-loop retro blitting and bleeping API. Months of polishing and tweaking later I ended up with FES.
      Some FES features:
      Pixel perfect rendering RGB and Indexed color mode, with palette swapping support Primitive shape rendering, lines, rectangles, ellipses, pixels Multi-layered tilemaps with TMX file support Offscreen rendering Text rendering, with text alignment, overflow settings, and custom pixel font support Clipping Sound and Music APIs Simplified Input handling Wide pixel support (think Atari 2600) Post processing and transition effects, such as scanlines, screen wipes, screen shake, fade, pixelate and more Deploy to all Unity supported platforms I've put in lots of hours into a very detail documentation, you can flip through it here to get an better glimpse at the features and general overview: http://www.pixeltrollgames.com/fes/docs/index.html
      FES is carefully designed and well optimized (see live stress test demo below). Internally it uses batching, it chunks tilemaps, is careful about memory allocations, and tries to be smart about any heavy operations.
      Please have a quick look at the screenshots and live demos below and let me know what you think! I'd love to hear some opinions, feedback and questions!
      I hope I've tickled your retro feels!



      More images at: https://imgur.com/a/LFMAc
      Live demo feature reel: https://simmer.io/@Dafu/fes
      Live blitting stress test: https://simmer.io/@Dafu/fes-drawstress
      Unity Asset Store: https://www.assetstore.unity3d.com/#!/content/102064

      View full story
    • By Dafu
      FES Retro Game Framework is now available on the Unity Asset Store for your kind consideration!
      FES was born when I set out to start a retro pixel game project. I was looking around for an engine to try next. I tried a number of things, from GameMaker, to Fantasy Consoles, to MonoGame and Godot and then ended up back at Unity. Unity is just unbeatable in it's cross-platform support, and ease of deployment, but it sure as heck gets in the way of proper retro pixel games!
      So I poured over the Unity pipeline and found the lowest levels I could tie into and bring up a new retro game engine inside of Unity, but with a completely different source-code-only, classic game-loop retro blitting and bleeping API. Months of polishing and tweaking later I ended up with FES.
      Some FES features:
      Pixel perfect rendering RGB and Indexed color mode, with palette swapping support Primitive shape rendering, lines, rectangles, ellipses, pixels Multi-layered tilemaps with TMX file support Offscreen rendering Text rendering, with text alignment, overflow settings, and custom pixel font support Clipping Sound and Music APIs Simplified Input handling Wide pixel support (think Atari 2600) Post processing and transition effects, such as scanlines, screen wipes, screen shake, fade, pixelate and more Deploy to all Unity supported platforms I've put in lots of hours into a very detail documentation, you can flip through it here to get an better glimpse at the features and general overview: http://www.pixeltrollgames.com/fes/docs/index.html
      FES is carefully designed and well optimized (see live stress test demo below). Internally it uses batching, it chunks tilemaps, is careful about memory allocations, and tries to be smart about any heavy operations.
      Please have a quick look at the screenshots and live demos below and let me know what you think! I'd love to hear some opinions, feedback and questions!
      I hope I've tickled your retro feels!



      More images at: https://imgur.com/a/LFMAc
      Live demo feature reel: https://simmer.io/@Dafu/fes
      Live blitting stress test: https://simmer.io/@Dafu/fes-drawstress
      Unity Asset Store: https://www.assetstore.unity3d.com/#!/content/102064
  • Popular Now