Exceptions

Pages: 123
@MiiNiPaa: I would argue that moving from a named variable is bad practice.

@helios: I do not design the standard C++ library.

@Disch: Use a pattern:
1
2
if(Image foo ("someimage.png"))
{
though even in the worst case a default image should be available meaning you don't need to use the pattern. (yes, it's a veiled is_valid, but it is now done at construction)
Disch wrote:
there's no way to detect that it happened from outside the class.
Logging.
Disch wrote:
Also, it does something other than what the user of the class intended.
I modify the content of "someimage.png" and run the program. Oh no! I should throw an exception because this is surely not what the user intended.
Disch wrote:
Silently faking a success is worse than failing. I would rather my code fail.
Then it is a context-dependent opinion. I don't want the player to be unable to play the game just because I forgot to include "someimage.png" in the patch.
Disch wrote:
I mean... how would you like it if a class like std::string did that? IE, instead of throwing an exception when it can't allocate more space, if it just didn't grow the string? That would be disasterous!
Out of memory: abort program. What could you do anyway? Once you start to suffocate there isn't much to alleivate the pain - the user is not going to plug in a second RAM chip and then let the program try again. Trying to save data? Bad idea - how do you know that's not how you got into this room filling with water? Throw an exception? Why? To let me know that one of my users didn't read the minimum RAM requirements on the box? Some meaningless line number of the one final allocation that pushed it over the edge? What am I supposed to do? I don't think sending more RAM to the user is part of the warranty.
@Disch: Use a pattern:
if(Image foo ("someimage.png"))


So... option #2... put the object in an error state.

That's acceptable now? I thought you were against that.

Logging.


I'm talking about silent to the program. IE, the program can't react to it.

Logging is for developer reading. Not program reaction. Unless you are having your program parse logs -- which would be insane.

I modify the content of "someimage.png" and run the program. Oh no! I should throw an exception because this is surely not what the user intended.


I don't understand what you are saying here.

Then it is a context-dependent opinion. I don't want the player to be unable to play the game just because I forgot to include "someimage.png" in the patch.


Throwing an exception does not mean the player is unable to play the game. It means your program is being alerted that something went wrong.

Not all exceptions are fatal.

Out of memory: abort program. What could you do anyway?


Switch to lower res resources.
Stream more data rather than load it all up front.

Or just print a message to the user so they know what happened rather than have the program abruptly crash.

Again... not all bad_alloc exceptions are fatal.
I do not design the standard C++ library.
I don't see how that's relevant.

if(Image foo ("someimage.png"))
Wot?

I don't want the player to be unable to play the game just because I forgot to include "someimage.png" in the patch.
Then it's not a problem of throwing or not throwing, it's a problem of bad design. Write a resource manager that checks at startup that all required resources are present, aborts if some isn't, and creates light resource objects that reference (without loading) those resources. If someimage_png.load() fails, then you know that something very bad happened, because a resource suddenly stopped existing.
Resources are part of the program. The developer forgetting to include part of the program is not a run time error. It should be evident before the user runs the program.
I would argue that moving from a named variable is bad practice.
1
2
3
std::string s;
std::getline(input, s);
some_func(std::move(s));
Alternatives? Also I am still trying to imagine how to access unnamed function arguments.

Also there is bunch of object which have invalid state when default constructed. Namely std::thread. If we would disallow constructing without associating a thread with it, we essentually forbidding to have arrays of threads.

Checks for image existense are not enough. For example there could be problem with decong image/video stream/compressed stream. What to do? Validate 20GB videofile completely before constructing stream from it? What to do if stream saw corrupted after validation?
load the appropriate inbuilt default asset for that asset type (e.g. pink-and-black checkerboard for missing texture)
I think it's worth pointing out that every successful game engine ever (possible exaggeration) does this.
this thread grew a lot!
LB wrote:
I have yet to research the new C++11 multithreading classes, but from my understanding, this code blocks until it can continue. I don't understand how it can fail.

It is specified to throw on error. When built on top of a typical posixy system, it would call pthread_mutex_lock which can fail with EAGAIN, EINVAL, ENOTRECOVERABLE, EDEADLK, and, for completeness, EOWNERDEAD (not really an error).

if I am understanding you correctly, the main advantage of exceptions in C++ is that they can be thrown from constructors?

It's not the only reason to use them, but it is the killer feature that makes exception-less C++ worthless, Google would be better off with another language (and they made one).
Last edited on
makes exception-less C++ worthless
You what? There's a lot of great C++ code that doesn't rely on exceptions. You can write great C++ code without ever throwing an exception.
Google would be better off with another language (and they made one).
Go isn't an all out replacement for C++ even at Google.
Disch wrote:
So... option #2... put the object in an error state.
0x0 image is not an error state.
Disch wrote:
I'm talking about silent to the program. IE, the program can't react to it.
If the program can't react to it then how do you plan to throw the exception?
Disch wrote:
I don't understand what you are saying here.
You were complaining that loading a default resource instead of the requeste one does something the user of the class did not intend. The user of the class should read the documentation.
Disch wrote:
Throwing an exception does not mean the player is unable to play the game. It means your program is being alerted that something went wrong.
From my OP: the exception is caught, logged, and ignored.
Disch wrote:
Switch to lower res resources.
What to do after that fails?
helios wrote:
Write a resource manager that checks at startup that all required resources are present
It is not possible to know what all required resources are. The server sends you them on the fly and then might never tell you to use them. On the serverside plugins load and unload while it is running and they take with them whatever resource loading/unloading logic they brought. Some resources get generated on the fly.
MiiNipaa wrote:
Alternatives? Also I am still trying to imagine how to access unnamed function arguments.
I don't like the design of the stream library and you try to use its design as an example of why I'm wrong. As for function arguments, could you give an example? I'm having trouble thinking of a case where I'd need to do that.
Lachlan Easton wrote:
I think it's worth pointing out that every successful game engine ever (possible exaggeration) does this.
Yes, I don't just say things because I can.
Cubbi wrote:
It's not the only reason to use them, but it is the killer feature that makes exception-less C++ worthless
Aside from memory allocation, why would I be throwing exceptions from ctors though?
It is not possible to know what all required resources are.
How is that possible? Are the resource paths or the resource themselves generated algorithmically?
For any resource load where the path is a constant, resource presence can be checked on plugin load.
So I can't play the game with MyFavoritePlugin just because someone forgot to include a sound for bunnies?
LB wrote:
Aside from memory allocation, why would I be throwing exceptions from ctors though?

First of all, memory is not some amorphous blob: I use several kinds of allocators, each allocating from a different heap, pool, or shared segment. Some of it can very well run out and it's not a valid reason to bring down a multibillion financial server.

And of course memory isn't the only thing the system can temporarily run out of: open files, semaphores, dynamic ephemeral ports, database connections, disk space. Besides environmental conditions, invalid values passed to constructor arguments can be unacceptable, as well as the values currently found in singletons/globals/Fortran commons that the constructor may need.
Perhaps I am just far too idealistic. I have a tendency to ignore problems related to things I cannot change. I cannot change the maximum number of file handles (why is there a maximum?) so I ignore that it exists. I admit it's not a good way of thinking.
Cubbi wrote:
Besides environmental conditions, invalid values passed to constructor arguments can be unacceptable, as well as the values currently found in singletons/globals/Fortran commons that the constructor may need.
Cubbi wrote:
That's called "wide contract", it's a whole different thread.
Would you like me to post a whole different thread?
So I can't play the game with MyFavoritePlugin just because someone forgot to include a sound for bunnies?
That's like saying "so I can't play my favorite game just because the program contains a type error?"
That's the whole point. If you make it impossible to load the plugin without all the required resources, you can't forget to include them. The user will never be given a plugin with missing resources in the first place.
Last edited on
A type error is different from a NYI.
Just wanted to chime in about the exceptions in game development subject. Interestingly enough exceptions are seeing quite wide use in game development and even in the newer generations of game engines (Unreal Engine uses them for one example).

Though anyways my point of view on the original subject is that exceptions not only make error handling easier to write they also make it so it is harder for you to make mistakes.

Let us consider what the code you would write to deal gracefully with a error would consist of.

1. Determining if an error has occured in the function you are calling.
2. Determine what the error is exactly.
3. If possible handle that error right there.
4. Propogate that error if it can't be handled right there.

Now on a performance note if we were to write out the above steps by hand to handle the errors all over our codebase it will more often then not be underoptimized and more then likely slower then exceptions would be (Unless you are a optimization freak and don't have better things to be optmizing or writing ;p).

Now on to a maintainability note, if we wrote the above by hand it would be significantly harder to maintain. Why? Simple because you have to propagate the errors by hand (Whereas exceptions automatically do this for you and is optimized in doing so).

This might not seem like a big deal when you are dealing with a small amount of these but when you start having to deal with manually propagating hundreds if not thousands of errors that might occur very deep in the code it gets very tedious and opens up a big portion for error.

For the readability I believe disch already touched on how exceptions are much more readable in code. So I won't go into that. Though I will say that exceptions are pretty much universally known, whereas your own error handling system is not.

So in short exceptions are much easier to read, faster then most error handling code, easier to maintain and they are universally known. In my mind it hard to see why someone wouldn't want to use exceptions for any program that is more then a few 100 lines of code that needs to handle errors gracefully.
Last edited on
Zereo wrote:
Though anyways my point of view on the original subject is that exceptions not only make error handling easier to write they also make it so it is harder for you to make mistakes.
From my point of view, exeptions make it easier to write code that requires error handling as well as easier to write code that can cause errors. They seem like an excuse to me.
Zereo wrote:
because you have to propagate the errors by hand
You are still thinking as if you are using exceptions, just without language-level support. Try thinking without exceptions.
Zereo wrote:
So in short exceptions are much easier to read, faster then most error handling code, easier to maintain and they are universally known.
Yes, yes, yes, and yes. But that doesn't make them seem right to me. There are plenty of analogies I could make and screw up relating to ancient medicinal practices. So I'll leave you to guess what I hope is an obvious analogy.


Exceptions are good at solving the problem they were meant to solve. But where did that problem come from? What caused us to need to invent exception handling? That is a greater concern for me.


EDIT: I just realized something interesting. In many scripting languages, trying to access a member of a class that doesn't is exist is neither a compile error nor a runtime error - you just get some default value. But what you guys have been telling me thus far is that this is bad. I don't use Python but my friend that does tells me it's all fine and dandy - so maybe I'm misunderstanding something or taking your words and applying them to things you didn't intend me to?
Last edited on
Continuing resource loader example:
If resource is no avaliable it would fall back to some default resource. But what if it too is not avaliable? What should happen?

Taking it even more: imagine that you develop this resource manager as a precompiled library. And it would be used by programs that both uses it as integral part of themself, or as non-important addition which program would be completely fine without. What should your library do? How it would fare without any kind of error reporting?
From my point of view, exeptions make it easier to write code that requires error handling as well as easier to write code that can cause errors. They seem like an excuse to me.


I am not sure what you mean by exceptions making it easier to write code that requires error handling. There isn't really a inbetween I don't think, if the code requires error handling it requires it whether or not you use exceptions is not a issue.

After reading over some of your previous posts it seems you seem to believe that it is possible to write code that doesn't have the probability for errors in it. This just isn't realistic in my opinion.

There will always be exceptional circumstances that are out of your control as a programmer and this is where exceptions come in (Hence the name). Yes it would be nice to handle everything is such a way as to not have a need for error handling but sadly that just isn't possible (And even if it was it would be much more work and probably less gain then just using error handling).

You are still thinking as if you are using exceptions, just without language-level support. Try thinking without exceptions.

I am not really sure what you mean here. If a error happens deep inside the callstack and can't be handled by that current system it will need to be propagated up the call stack to a system that can. Propagating a error to a system that can handle it isn't unique to exceptions.

Yes, yes, yes, and yes. But that doesn't make them seem right to me. There are plenty of analogies I could make and screw up relating to ancient medicinal practices. So I'll leave you to guess what I hope is an obvious analogy.


Exceptions are good at solving the problem they were meant to solve. But where did that problem come from? What caused us to need to invent exception handling? That is a greater concern for me.

Again I am not really sure what you mean here.
Last edited on
Zereo wrote:
I am not sure what you mean by exceptions making it easier to write code that requires error handling.
If it is difficult to do something, you will generally find ways to avoid doing it. But if it's easy to do something, you can easily cave in and do it. I will walk around a lake rather than swim across it, but if now you give me a boat I will do that instead of walking around the lake. Now I have to worry about the boat sinking, or falling overboard.
Zereo wrote:
After reading over some of your previous posts it seems you seem to believe that it is possible to write code that doesn't have the probability for errors in it. This just isn't realistic in my opinion.
I'm definitely getting the sense that I am too idealistic.
Zereo wrote:
I am not really sure what you mean here. If a error happens deep inside the callstack and can't be handled by that current system it will need to be propagated up the call stack to a system that can.
You hire a company to build a house for you somewhere. One day the company calls and says it's your responsibility to repair the roof that caved-in from heavy snowfall. "Sorry, we don't offer repair services."
Zereo wrote:
Again I am not really sure what you mean here.
Why do errors happen? Errors are an implementation detail. They should be abstracted away and dealt with internally.
Last edited on
They should be abstracted away and dealt with internally.
What if I want to know that something bad happened?

You hire a company to build a house for you somewhere. One day the company calls and says it's your responsibility to repair the roof that caved-in from heavy snowfall. "Sorry, we don't offer repair services."
You hire a company to build a house for you somewhere. One day the roof caves in and, rather than calling you to inform you, they make an exact duplicate of the roof out of matches and glue because that's the best they had to work with. The next winter when you move in, it all falls down on you and kills you.
Pages: 123