Archived

This topic is now archived and is closed to further replies.

aboeing

exceptions

Recommended Posts

aboeing    180
Hi, I know there have been a number of previous threads on this topic, but I havent found any satisfactory explanations. The question basically is, why would you want to use C++ exception handling? (I understand that you want to use it for detecting very low level errors, but most of the time these errors dont happen - Im talking about as a general error handling mechanism) What advantages does it have over, say a global variable indicating whether an error occured and what it was? What advantages does it have over having a base class with an error variable, a pointer to its parent, and propogating the errors like that? With both these approaches you can simply put all your code somewhere and check for errors when its convenient, and dont need to worry about ugly nested try{}catch{} statements. Also: Do you always have to catch all your exceptions if you dont want your program to crash? (eg: loadtexture causes an exception, but its not critical, so I shouldn''t have to deal with it..) What are the performance issues related to exception handling? (If your already using virtual functions / RTTI is there added overhead?, Can exception handling be turned on/off for certain functions/classes?) What support does the OS need to supply for exception handling? (is it just a fancy term for an interrupt?) Thanks!

Share this post


Link to post
Share on other sites
Matsen    132
No one seems to answer, so I'll give it a shot...

What advantages does it have over, say a global variable indicating whether an error occured and what it was?

Simplicity. You don't have to check that global variable after every time you perform something and return some error value through a jungle of if (not error) 'do this' else 'do that' . You just do it (well, perhaps not just ). Also, some designs would not be possible without exceptions as a way of communicating an error; boost::lexical_cast would be an example. Let's say you are writing a templated container class, taking any type T. Inside the container, you make a copy of everything that is added to it. How should T tell the container and the user of the container that some error occured while copying? You could use some method is_ok() and return false, if T is a class, but that would rule out any primitive type and the container can only handle classes that implement is_ok(). It's not so generic any more. I don't know if my example was any good, but the point is that exceptions provide a standard way of handling errors. The container need only to provide some documented level of exception safety and leave the rest to the user.

Further, global variables has their own set of problems.

With both these approaches you can simply put all your code somewhere and check for errors when its convenient, and dont need to worry about ugly nested try{}catch{} statements

When it's convenient? Wouldn't it be convenient to handle errors when they occur? If it's ok for you to handle some errors when it's convenient, then don't use exceptions for those erros. Exceptions are best used for exceptional cases. This does not mean that it has to be some unrecoverable hardware error, when your home is about to explode, or etc, as I've gotten the impression that some might think. What's exceptional and what's not, depends on what you are doing. This does not mean that exceptions should replace simple return values.

Do you always have to catch all your exceptions if you dont want your program to crash?

Yes.

is there added overhead?

AFAIK, performance is only affected when setting up a try-catch block or when the exception is thrown.

What support does the OS need to supply for exception handling?

The OS has nothing to do with C++ exceptions. For Windows, there is also Structured Exception Handling, which is something different, but has a similar construct.

Edit: spelling

[edited by - Matsen on October 12, 2003 4:08:04 PM]

Share this post


Link to post
Share on other sites
antareus    576
quote:
Original post by aboeing
(I understand that you want to use it for detecting very low level errors, but most of the time these errors dont happen - Im talking about as a general error handling mechanism)


It *is* a better general purpose error handling mechanism.

Since it unwinds the stack EVERYTHING along the way can clean up or not handle the exception as it happens. Handlers can rethrow different exceptions or take actions like rollback a database to prevent destructive changes from happening.

A global variable holding the exception is okay, but then you have to make that local to the thread. Once you get around that, programs don''t have to check it, and it encourages a sort of irresponsible coding style where "this works most of the time." Then when something doesn''t work, go run post on Gamedev! If you don''t have an exception then your program stops RIGHT there and you can look at the exception and determine what happened if you provide enough information.

Also, using return values to indicate success/failure really isn''t necessary nowadays. Your ''nominal'' code path does not turn into a gigantic indentation because of all the if''s. The error handling logic is separate from the normal logic.

Share this post


Link to post
Share on other sites
Arild Fines    968
quote:
Original post by Matsen
What support does the OS need to supply for exception handling?

The OS has nothing to do with C++ exceptions. For Windows, there is also Structured Exception Handling, which is something different, but has a similar construct.


On Windows, C++ exceptions are implemented on top of SEH.

Share this post


Link to post
Share on other sites
Matsen    132
quote:
On Windows, C++ exceptions are implemented on top of SEH.
Yes, that''s true for a Microsoft compiler, but what about other compilers, such as gcc?

Share this post


Link to post
Share on other sites
Fruny    1658
The question basically is, why would you want to use C++ exception handling?

Because it is easier and safer than propagating errors by hand.
Exceptions propagate until they find the appropriate handler.

What advantages does it have over, say a global variable indicating whether an error occured and what it was?

Exceptions are always detected. Programers quite often forget to check error codes.

What advantages does it have over having a base class with an error variable, a pointer to its parent, and propogating the errors like that?

You can already arrange exceptions in a hierarchy and catch the base exceptions. I don''t quite understand the approach you are suggesting ? Is the base class an exceptiobn class ? Is it a base class of the objects you manipulate (setting the error member when an error occurs) ?

With both these approaches you can simply put all your code somewhere and check for errors when its convenient, and dont need to worry about ugly nested try{}catch{} statements.

Instead you will have to worry about whatever structure YOU put in place to emulate exceptions. Personally, I prefer using a construct that is directly supported by the language than a half-baked, untested alternative that may require me to actually do more work.

If you used the RAII idiom ( "Ressource Acquisition Is Initialisation" ) - Acquiring resources in constructors, releasing them in destructors, you don''t even have to worry about things like closing files, releasing locks, freeing memory blocks ...

Do you always have to catch all your exceptions if you dont want your program to crash?

Yes

(eg: loadtexture causes an exception, but its not critical, so I shouldn''t have to deal with it..)

If it is not an error, don''t throw an exception.

What are the performance issues related to exception handling?

None unless an exception is actually thrown, at which point you shouldn''t care for performance anyway - something wrong happened, you need to fix it before moving on. try is practically free, it is throw that is expensive.

Can exception handling be turned on/off for certain functions/classes?

Not in standard C++. Your compiler may let you do it as an extension.

What support does the OS need to supply for exception handling?

I don''t know.

(is it just a fancy term for an interrupt?)

No. Exceptions trigger a stack unwinding within your program until the appropriate handler is found (or the exception leaves main(), at which point terminate() is called). Interrupts suspend the execution of your program to execute a handler that ''lives'' outside of your program (possibly in kernel-land).


[ Start Here ! | How To Ask Smart Questions | Recommended C++ Books | C++ FAQ Lite | Function Ptrs | CppTips Archive ]
[ Header Files | File Format Docs | LNK2001 | C++ STL Doc | STLPort | Free C++ IDE | Boost C++ Lib | MSVC6 Lib Fixes ]

Share this post


Link to post
Share on other sites
aboeing    180
Hi,
First of all, thank you everyone for your feedback!

Re:Matsen:
"Simplicity."
-> to me, exceptions seem less simple.
try {x;} catch() {}
is more code than:
x; if(error) {}

"If it's ok for you to handle some errors when it's convenient, then don't use exceptions for those errors"
This is what I figured, in which case I would need my own error handling system anyway, so why bother with exceptions?

"AFAIK, performance is only affected when setting up a try-catch block or when the exception is thrown."
Well, this is good, at least I dont have to be afraid of using them =)

Re:antareus:
"Also, using return values to indicate success/failure really isn't necessary nowadays. Your 'nominal' code path does not turn into a gigantic indentation because of all the if's. The error handling logic is separate from the normal logic. "
How do you seperate error handling from normal code with exceptions? Are you just saying that try{}catch{} is seperating it? It would seem nicer to have a seperate HandleError method for each class that would be automatically called if something went wrong.

Also, as I suggested, your error variable could maintain information as to where the error occured (__LINE__,__FILE__ etc) so I dont see the point of using exception handling for this reason.

Re:Fruny:
"Because it is easier and safer than propagating errors by hand."
Is this safer meaning that I'm likely to make a mistake in my error handling code, or do you mean something else?

"Exceptions are always detected. Programers quite often forget to check error codes."
This is also one of my major concerns about exceptions. Writing code like try{CreateDXEngine();}catch(){} try{CreateTexture();}catch(){} try{CreateMesh();}catch() try{Render();}catch() seems like a very ugly way for the end user to use a system.

"Ressource Acquisition Is Initialisation"
Agreed that exceptions would work quite nicely in this design, but I dont think its possible to develop my entire system this way.

"If it is not an error, don't throw an exception."
But what now? now I need some kind of not-exception error handling mechanism, and as I said before, doesnt this make exceptions redundant?

"Exceptions trigger a stack unwinding"
Sorry if I dont really understand, but does this mean extra information needs to be passed on the stack with every function call/whathaveyou?

-=-=-=--=-=-=--=-=-=--=-=-=--=-=-=--=-=-=--=-=-=--=-=-=--=-=-=-

From the overall response I can see that people like exceptions because they are language specific and they force users to deal with errors that happen. (personally, I'm not a fan of this, as users generally dont deal with errors, and I would prefer for my program to continue trying to run than have it exit and say "exception thrown blablabla")

The responses indicate that there are no performance reasons to not use exceptions, so I should use them.

Also, people say only to use exceptions for exceptional circumstances (makes sense.)
So this means you'll want some other method of error handling aswell. So, where do you draw the line? And what is the best method for doing so?

What I had in mind (Re:Fruny:"the approach you are suggesting?" ) was something like:

class Base {
struct error_struct; //contain info such as __LINE__,etc.

Base *parent; //point to my 'creator'

void SetError(an_error_struct) {
this->error_struct=an_error_struct
parent->notify_an_error_occured_and_call_set_error_if_appropriate
}
}

class Texture{
void Loadtexturefromfile(){
if(filenotfound) SetError();
}
}

class Model {
void SetupModel() {
Texture *mytex = Create("Texture",this); //automagically set parent

//Load a bunch of textures

If(erroroccured) {
deal with it, if the texture wasnt critical to gameplay we can render the model anyway
}
}
}

you get the general jist of it.. (you could easily extend this so that the base class had a HandleErrors() method that was automatically called as the error propogated..)

Thanks.

(edit:fixed italics)

[edited by - aboeing on October 13, 2003 8:57:03 AM]

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
What about this code then:

int* x1;
int* x2;
int* x3;
int* x4;
int* x5;

try
{
x1 = new int;
x2 = new int;
x3 = new int;
x4 = new int;
x5 = new int;
}
catch(...)
{
std::cout << "there was an error..." << std::endl;
}


If you would write the same code with if''s :

int* x1 = new int;
if(x1 == NULL) std::cout << "there was an error" << std::endl;
int* x2 = new int;
if(x2 == NULL) std::cout << "there was an error" << std::endl;
int* x3 = new int;
if(x3 == NULL) std::cout << "there was an error" << std::endl;
int* x4 = new int;
if(x4 == NULL) std::cout << "there was an error" << std::endl;
int* x5 = new int;
if(x5 == NULL) std::cout << "there was an error" << std::endl;

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
quote:

deal with it, if the texture wasnt critical to gameplay we can render the model anyway



!!!LMAO!!!

Share this post


Link to post
Share on other sites
aboeing    180
AP #1:
True, perhaps exception handling should be used for out-of-memory checks aswell, although in my experience I dont often need to do something like that. (most of the time my classes only have 1 or 2 non-class objects that need to be created).

Then again, do we consider out-of-memory an exceptional case?
I probably would. The other instances I would use it are for standard functions which could fail, or when you are calling a users-plugin which could have bad code in it. (naturally, all the code I would write would work perfectly, so this wouldn''t be necessary for me ) Any other opinions?
(eg:
FILE *fp;
try {
fp = fopen(filename, "a");
} catch (...) {
#ifdef WIN32
MessageBox(NULL,"Serious error has occured, could not call fopen!","Log::debug",MB_OK|MB_ICONWARNING);
#endif
return;
}
if (fp==NULL) return some_error;
)

AP #2:
Think of a quake3 map, and not all the textures are available for the map, the engine should still load and render what it can.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
quote:
Original post by Anonymous Poster
What about this code then:

int* x1;
int* x2;
int* x3;
int* x4;
int* x5;

try
{
x1 = new int;
x2 = new int;
x3 = new int;
x4 = new int;
x5 = new int;
}
catch(...)
{
std::cout << "there was an error..." << std::endl;
}





Thats very poor exception safe code, if the last call to new throws an exception then you have just leaked a lot of code into the freestore

Probably better using the RAII model as mentioned by Fruny, and initialising smart pointers with your resource

Share this post


Link to post
Share on other sites
SabreMan    504
quote:
Original post by aboeing
-> to me, exceptions seem less simple.
try {x;} catch() {}
is more code than:
x; if(error) {}

Where did you pull the above code from? I''d guess that it would be more convenient for you if usage of the exception mechanisms did lead to an increase in your code base, because then you could simply disregard exceptions and avoid spending the mental effort in learning how to use them. With that in mind, you appear to have contrived a trivial example which seems to serve as evidence for your (apparent) initial premise (that exceptions are not worthwhile). This is a form of logical fallacy known as `Begging the Question''. IME, your code sample is not indicative of a good error-recovery strategy implemented via exceptions.

My suggestion is that you begin with the premise that exceptions may be useful, spend some time learning how they should be used, and then derive a conclusion from the experience.
quote:

This is what I figured, in which case I would need my own error handling system anyway, so why bother with exceptions?

Either its an exceptional situation or it isn''t. For example, reaching end-of-file is not an exceptional situation, so you would use a simple return code to indicate the non-exceptional change of state. However, if you open a file needed by the application and it doesn''t exist, that would probably be an exception.
quote:

Well, this is good, at least I dont have to be afraid of using them =)

You mean your only fear is whether exceptions impose any otherwise avoidable runtime overhead. The usual comments about premature optimisation apply.
quote:

How do you seperate error handling from normal code with exceptions? Are you just saying that try{}catch{} is seperating it? It would seem nicer to have a seperate HandleError method for each class that would be automatically called if something went wrong.

try-catch might not be the best conceivable mechanism for separating concerns, but it is better than manually propagating return codes, where error-recovery logic is interspersed with program logic. An even better approach might be achievable through use of Aspects in an Aspect-Oriented language.
quote:

Also, as I suggested, your error variable could maintain information as to where the error occured (__LINE__,__FILE__ etc) so I dont see the point of using exception handling for this reason.

You can maintain the same information with exceptions.
quote:

This is also one of my major concerns about exceptions. Writing code like try{CreateDXEngine();}catch(){} try{CreateTexture();}catch(){} try{CreateMesh();}catch() try{Render();}catch() seems like a very ugly way for the end user to use a system.

What on earth do you mean? The end-user of a system does not (should not) be dealing with any of the source-code whatsoever. Do you mean the programmer of the system? If so, my initial comments apply - where did you get the above code from? Its not typical of how (good) programmers use exceptions.
quote:

Agreed that exceptions would work quite nicely in this design, but I dont think its possible to develop my entire system this way.

It''s exactly the way many programmers develop entire systems, including myself. Obviously, it is possible. I''d also contend that its desirable.
quote:

"If it is not an error, don''t throw an exception."
But what now? now I need some kind of not-exception error handling mechanism, and as I said before, doesnt this make exceptions redundant?

No. It means that you don''t abuse exceptions. Going back to my previous example, if you use exceptions for reporting EOF, then that would be an abuse.
quote:

Sorry if I dont really understand, but does this mean extra information needs to be passed on the stack with every function call/whathaveyou?

No. It uses the information which is on the stack regardless of whether exceptions are used.
quote:

From the overall response I can see that people like exceptions because they are language specific and they force users to deal with errors that happen.

No, neither of those are the reasons that people are saying they like exceptions, and I don''t know how you managed to come up with them. Language specificity is irrelevant, and users (do you mean programmers) are *not* forced to deal with errors.

People like exception mechanisms because they generate code which would otherwise be written manually. When used judiciously, they can significantly reduce the amount of code required for a program.
quote:

(personally, I''m not a fan of this, as users generally dont deal with errors, and I would prefer for my program to continue trying to run than have it exit and say "exception thrown blablabla")

Actually, users do often deal with generated errors (that''s if you actually mean "users" this time). For example, MS provides dialog boxes specifically intended to convey error information to a GUI user in order to determine how to continue from an invalid program state. However, exceptions do not force you to report errors back to users. If you don''t want to report an error, you don''t have to throw an exception, or you can have a handler on the outer-loop of your program (in fact, you should do something like this to report errors to users rather than let the default-handler do its stuff).
quote:

So this means you''ll want some other method of error handling aswell. So, where do you draw the line?

It''s debatable whether a non-exceptional reporting mechanism is really an "error handling" system - it will just be reporting the normal return codes of functions. However, knowing where to draw the line is the result of experience. You will not gain that body of experience by memorising a few second-hand factoids completely divorced from the experience which led to them.

Share this post


Link to post
Share on other sites
DrPizza    160
quote:
For example, reaching end-of-file is not an exceptional situation

Isn''t it? It seems to me to depend on what you''re doing.

If you were performing random access to a file, hitting EOF -- which is just one position out of millions or billions -- is certainy exceptional, and perhaps even indicative of an error, either in calculating an offset, or a corrupt file, or something similar. So throwing seems quite tolerable.

On the other hand, if your intent was to consume an entire file in one pass, EOF seems entirely expected -- when reading a file from start to finish EOF is always going to be hit. So throwing seems the wrong thing to do.

Share this post


Link to post
Share on other sites
Fruny    1658
quote:
Original post by DrPizza
If you were performing random access to a file, hitting EOF -- which is just one position out of millions or billions -- is certainy exceptional, and perhaps even indicative of an error, either in calculating an offset, or a corrupt file, or something similar. So throwing seems quite tolerable.



Which is why the standard iostream library give you the option of throwing on EOF :


std::ifstream ifs;
ifs.exceptions( std::ios_base::eofbit );

try
{
//

//

// do lots of I/O

//

//

}
catch( std::ios_base::failure& e )
{
//

// fix it !

//

}



[ Start Here ! | How To Ask Smart Questions | Recommended C++ Books | C++ FAQ Lite | Function Ptrs | CppTips Archive ]
[ Header Files | File Format Docs | LNK2001 | C++ STL Doc | STLPort | Free C++ IDE | Boost C++ Lib | MSVC6 Lib Fixes ]

Share this post


Link to post
Share on other sites
Fruny    1658
First, I need to state that I agree with Sabre Man. Or rather that I am afraid he''ll tear me to shreds if I dare disagree

to me, exceptions seem less simple.
try {x;} catch() {}
is more code than:
x; if(error) {}


Your system only handles the *last* error that occured by the time you reach your error handler. Exceptions handle the very first one - there is no time for other errors to occur.

try { x; y; z; } catch(...) { /* ... */ }
is very different from
x; y; z; if(error) {}

This distinction is even more important when you start trying to propagate your errors : foo calls bar which calls baz and quux, one or both of which may cause an error that needs to be handled in foo.
If both baz and quux cause an error, what does foo get ? Look at how OpenGL handles error (admittedly non-fatal) for an example.

This is what I figured, in which case I would need my own error handling system anyway, so why bother with exceptions?

Because exceptions are already built in, and your are proposing to duplicate the work for absolutely no benefit.

Well, this is good, at least I dont have to be afraid of using them =)

Don''t let your fear of the unknown stop you from learning the full range of the language

How do you seperate error handling from normal code with exceptions? Are you just saying that try{}catch{} is seperating it?

Yes.

It would seem nicer to have a seperate HandleError method for each class that would be automatically called if something went wrong.

Call it from your exception handler. That way it will be ''automatically'' called when you throw an exception. As an added benefit, since exceptions are objects, you can store as much information as you need about the error in one, and it will be available to your handler. The exception variable in the catch statement is not just there for shows, you know.

Also, as I suggested, your error variable could maintain information as to where the error occured (__LINE__,__FILE__ etc) so I dont see the point of using exception handling for this reason.

See above.

Is this safer meaning that I''m likely to make a mistake in my error handling code, or do you mean something else?

You''re not just likely. You will make a mistake. At least on your first implementation. Remember that you must not let a critical error unhandled. And consider again my comments about what happens when several functions trigger errors.

This is also one of my major concerns about exceptions. Writing code like

try { CreateDXEngine(); } catch(...) {}
try { CreateTexture(); } catch(...) {}
try { CreateMesh(); } catch(...) {}
try { Render(); } catch(...) {}

seems like a very ugly way for the end user to use a system.

Throw when you need, don''t throw when you needn''t. Don''t rule out exceptions just because they do not fit your example

Anyway, in this very example, there is not much point to move on to Render() if the previous steps have failed (point taken about CreateTexture, though). So you can do it as follow :

try { 
CreateDXEngine();
CreateTexture();
CreateMesh();
Render();
}
catch(...)
{}

If a failed step prevents you from completing the next, you are much better off with exceptions than with nested ifs or staggered returns.

Remember - you only put a try-block at the point where you will be handling the error. Plus you can handle it and rethrow if you want ...

Agreed that exceptions would work quite nicely in this design, but I dont think its possible to develop my entire system this way.
That''s how they have been designed to work, and that''s the method advocated by B.Stroustrup. Entire systems have been designed that way.

But what now? now I need some kind of not-exception error handling mechanism, and as I said before, doesnt this make exceptions redundant?

You need to consider carefully if you can afford not to check for an error. If you can, it is not an error. What will happen if I call Render and the call to CreateTexture failed ? What if CreateDXEngine failed ?

Checking return values is fine if not checking won''t cause problems. Once again, I''ll point you to OpenGL''s error handling. If you do something wrong, OpenGL silently fails. That''s ok so long as you don''t consider image correctness to be critical (I know people who make computations using GL-generated images!). If you do, your code will be peppered with checks worse than what you get with exceptions.

As for redundancy, if statements make switch/case redundant; for loops make while and do-while redundant. Use the right tool in the right place.

Sorry if I dont really understand, but does this mean extra information needs to be passed on the stack with every function call/whathaveyou?

That would depend on the implementation. I can imagine a few different ways of doing it, either pushing the address of the topmost handler with each function, or keeping a separate stack of handler, adjusted with every try block... But of course I could be dead wrong.

Great, now I can''t get it out of my mind. I''ll have to check out the g++ source code and figure this out...

So this means you''ll want some other method of error handling aswell. So, where do you draw the line? And what is the best method for doing so?

I unfortunately have no answer to that question. Programming is all about dealing with tradeoffs, and finding the point you are comfortable with (while still having your program generate correct output).

Base *parent; //point to my ''creator''

So you''re having everything derive from Base.
I don''t think that''s a good idea... but that''s just me.

Texture *mytex = Create("Texture",this); //automagically set parent

Well, it''s not magic, you have to do it yourself, and it''s an additional clunkiness that intrudes in your class design.

deal with it, if the texture wasnt critical to gameplay we can render the model anyway

Rather than have an error at that point, I''d design my render function in a way that it can deal with missing textures without being told an error occured .



[ Start Here ! | How To Ask Smart Questions | Recommended C++ Books | C++ FAQ Lite | Function Ptrs | CppTips Archive ]
[ Header Files | File Format Docs | LNK2001 | C++ STL Doc | STLPort | Free C++ IDE | Boost C++ Lib | MSVC6 Lib Fixes ]

Share this post


Link to post
Share on other sites
DrPizza    160
quote:
Which is why the standard iostream library give you the option of throwing on EOF

I was going to mention that, but felt it unnecessary, as I''m sure SabreMan knows. Anyway, I feel that it''s a sound (albeit unusual) design; the main point was that I disagree with his characterization of the nature of hitting EOF.

That''s the biggest problem that I see with exceptions; it''s not clear what''s exceptional and what''s not.

Share this post


Link to post
Share on other sites
Shannon Barber    1681
You throw an exception if there is nothing else to do, no way the program can continue proper execution under the current conditions. Otherwise, the exception is gratuitous or the program is malformed.

If you know C, C++ exceptions are built upon setjmp and longjmp, but automated.

Share this post


Link to post
Share on other sites
aboeing    180
Hi,
Again, Thank you for your replys, and sorry for causing a bit of confusion.

For me, the "user" is the programmer who is going to be using my library. eg: someone writing plugins. I will try to use a different terminology in future to avoid confusion. Apologies.

Second,
Also, as I suggested, your error variable could maintain information as to where the error occured (__LINE__,__FILE__ etc) so I dont see the point of using exception handling for this reason.
Sorry, I should have made myself clearer. What I meant here, was that someone was saying you should use exceptions because they tell you where the error occured. I was pointing out that you dont need to use exceptions in order to know where the error occured.

Re:SabreMan:

Where did you pull the above code from?
As far as I know, thats how you use exceptions? Please correct me if im wrong, as that would change things dramatically.

I'd guess that it would be more convenient for you if usage of the exception mechanisms did lead to an increase in your code base, because then you could simply disregard exceptions and avoid spending the mental effort in learning how to use them.
Well, uh, yes? If I can use some other mechanism which allows me to obtain the same functionality (that is, as a error handling mechanism) as exceptions, but requires me to do less typing, and allows me to be 'lazyer' then I will use it. Its like using smart pointers, not a language feature, but once implemented allows you to be lazy. This, in my opinion, is a good(tm) thing.

With that in mind, you appear to have contrived a trivial example which seems to serve as evidence for your (apparent) initial premise (that exceptions are not worthwhile). This is a form of logical fallacy known as `Begging the Question'. IME, your code sample is not indicative of a good error-recovery strategy implemented via exceptions.

This is true, I was of the opinion that exceptions are not worthwhile, Im sorry if I have been non-objective, I have been trying. The entire reason I started this thread was because I have looked through a large number of projects and most dont use exceptions, but some did (SIGEL, OGRE). These people obviously had reasons for using them, so I figured I was missing something.

My suggestion is that you begin with the premise that exceptions may be useful, spend some time learning how they should be used, and then derive a conclusion from the experience.
I think I did. I think I know how they are used, but came to the conclusion that they were not very usefull at all. As I said, other people have used them extensivly, so I figured I was missing something.

Just to clarify, when I was talking about usefullness of exceptions I mean in a system of communicating errors between classes and soforth (ie: exception VS return codes), not for detecting errors which can not otherwise be detected (as in my fopen example - obviously they are very usefull for that).

Either its an exceptional situation or it isn't. For example, reaching end-of-file is not an exceptional situation, so you would use a simple return code to indicate the non-exceptional change of state. However, if you open a file needed by the application and it doesn't exist, that would probably be an exception.
Okay, so you are saying that using a return code is your prefered method of indicating errors aswell? So why use exceptions for returning some errors and not others? This is the point which confuses me.

You mean your only fear is whether exceptions impose any otherwise avoidable runtime overhead. The usual comments about premature optimisation apply.
Well, operating system support aswell. I intend to run some of my libraries on a 25mHz controller. I do not believe this is a case of premature optimization, as whether you use exceptions or not has a big influence on how you would design your system.

try-catch might not be the best conceivable mechanism for separating concerns,
Which is what I am suggesting...
but it is better than manually propagating return codes, where error-recovery logic is interspersed with program logic.
I dont really agree with you here, but fair enough..
An even better approach might be achievable through use of Aspects in an Aspect-Oriented language.
And this kind of reply is exactly what im looking for. Something better than exceptions and return codes. Unfortuantely your suggesting an entierly different language (right?), which is not an option for me. Any other suggestions? (can this be 'emulated' in C++?)

If so, my initial comments apply - where did you get the above code from? Its not typical of how (good) programmers use exceptions.
I was under the impressions that this is how you use exceptions?
I should have mentioned in my example that rendering may continue if CreateTexture or CreateMesh fail. In which case you need seperate try(..)catch() statements? Are there other ways to use exceptions? (again, map example, mesh&texture may come from a vase, whos presence is not critical in rendering the map)

It's exactly the way many programmers develop entire systems, including myself. Obviously, it is possible. I'd also contend that its desirable.
Sorry, I'm wrong. What I meant to say is that for my situation this is not preferable. At least I dont think so.

No. It means that you don't abuse exceptions.
So what is an abuse of exception? Using an exception for anything other than where the thing we are 'try'ing could possibly crash? (eg: only as I have suggested in the fopen example?)

People like exception mechanisms because they generate code which would otherwise be written manually. When used judiciously, they can significantly reduce the amount of code required for a program.
I am guessing you mean that this is when you are trying a whole bunch of critical things in a row which could fail that rely on another? I dont see this happening all too often.
If they are not critical, as I have said, I dont see exceptions being advantageous over return codes.

Actually, users do often deal with generated errors (that's if you actually mean "users" this time).
Yes I do, sorry.
For example, MS provides dialog boxes specifically intended to convey error information to a GUI user in order to determine how to continue from an invalid program state.
I had a different reply to this, but It basically boils down to this: how many times after seeing one of those error messages have you been able to restore the system to a useable state?
Regardless, you make a good point, might aswell hope for the best.

It's debatable whether a non-exceptional reporting mechanism is really an "error handling" system - it will just be reporting the normal return codes of functions.
I do consider this an error handling system, as you can use it to determine whether errors happend or not, and then deal with the situation accordingly.

However, knowing where to draw the line is the result of experience. You will not gain that body of experience by memorising a few second-hand factoids completely divorced from the experience which led to them.
Agreed, but what else can I hope for? I dont have time to implement my whole system, get it wrong, and re-implement it again.

Re:Fruny:
Your system only handles the *last* error that occured by the time you reach your error handler. Exceptions handle the very first one - there is no time for other errors to occur.
Agreed. In my experience there are not a lot of times when I am doing a lot of exceptional errors in a row.

try { x; y; z; } catch(...) { /* ... */ }
is very different from
x; y; z; if(error) {}
Because exceptions are already built in, and your are proposing to duplicate the work for absolutely no benefit.

The benefit is being able to deal with situations that are not-exceptional more easily. (refer back to my model-making scenario, this might not be common for your systems, but that sort of thing is very common for mine (re:Don't rule out exceptions just because they do not fit your example
)) Also, return codes seem more common and so plugin-developers wouldn't have to worry about learning exceptions.

Call it from your exception handler. That way it will be 'automatically' called when you throw an exception.
Hey. Thats a good idea.
SaberMan/Anyone: Is this how you implement AspectOP in C++?

If you do, your code will be peppered with checks worse than what you get with exceptions.
Good point. So it would be nice if we could choose to either ignore non-critical errors or be forced to deal with them.
Any ideas? Perhaps (error handler code) :
if (g_reportall_flag)
throw something;
else
just add another entry to your log. plugin-developer can check this when(if) they want. (read:return code)

Maybe the solution to my complaints is to use both methods simultaneously. Ideas anyone?

Great, now I can't get it out of my mind. I'll have to check out the g++ source code and figure this out...
Appreciated.

So you're having everything derive from Base. I don't think that's a good idea... but that's just me.
A few people have this issue. Any reason? Actually thats a bit off topic, lets just ignore this

//automagically set parent
Well, it's not magic

Sorry, I wrote out the code so people could better understand what was going on. This would be replaced by a macro
CREATE(x) pluggablefactory->Create(#x,this)
wow. 'magic!'

Rather than have an error at that point, I'd design my render function in a way that it can deal with missing textures without being told an error occured
Not sure what you mean..

Re: Pizza,Magmai
That's the biggest problem that I see with exceptions; it's not clear what's exceptional and what's not.
You throw an exception if there is nothing else to do, no way the program can continue proper execution under the current conditions.
This sounds good to me. I imagine this situation is rare? (has been in my experience). In which case you should not be using exceptions as your general error handling mechanism? [or again, maybe some way to use both seamlessly?]

Thanks again guys.

[edit:fixed italics & smileys]

[edited by - aboeing on October 13, 2003 12:11:56 AM]

Share this post


Link to post
Share on other sites
Glass_Knife    8636
I have a feeling this comment is going to start something, but I can''t resist!
Once upon a time, there was Fortran and Pascal and Basic...
Then came C. "What is all this printf, pointer, struct stuff?" they asked. "Who needs this?" They lost, and C was the way. Then came c++. "What is all this class, inheritance, virtual function, template stuff? Who needs this?" They lost too. C++ forever!!! Then came Windows. Dos programers said no way, and they lost. Then came Java. "That''s just a lame scripting language." Nope! They lost too. Now we''ve got a whole new gang of programming languages. VB.net, C#.net, and java 2.0 all OOP style. Maybe C++ exceptions were not understood in the beggining, and abused, used wrong, ect...
But, all the new stuff uses it for everything. Why use it? Because that''s how its done now, and C++ is going bye bye with Fortran, Pascal, BASIC, and C. There are no globals in the new style of programming, and there might never be another Global again. You don''t see GOTO anymore, do you?

Just another way to look at it.

Glass_Knife
I think, therfore I am.
I think?

Share this post


Link to post
Share on other sites
SabreMan    504
quote:
Original post by DrPizza
Isn't it? It seems to me to depend on what you're doing.

I'll go along with that, particularly since I was going to state that whether or not something is an exception is dictated by the problem domain. I was trying to find a common example to help aboeing understand the difference between exceptional and non-exceptional situations, but I probably over-generalised. I still think the example helps with understanding that difference as long as the reader is trying to understand and not being obtuse. (That's not meant to imply anyone in this thread is being obtuse).


[edited by - SabreMan on October 14, 2003 5:36:57 AM]

Share this post


Link to post
Share on other sites
SabreMan    504
quote:
Original post by aboeing
Sorry, I should have made myself clearer. What I meant here, was that someone was saying you should use exceptions because they tell you where the error occured. I was pointing out that you dont need to use exceptions in order to know where the error occured.

Exceptions (in C++) don't automatically tell you where an error occurred. You have to add context information if that's what is required.
quote:

Okay, so you are saying that using a return code is your prefered method of indicating errors aswell?

No. I'm trying to point out that some so-called `errors' are not errors in the context of a particular problem, and can be reported via the normal return of a function. Technicalities aside, my example was that EOF might not really be an error - it might be a perfectly expected, or even required situation. To interpret an expected situation as an error seems quite perverse. Exceptions and return-codes are not mutually exclusive. As with many things in programming, it takes experience to know which one to use when.
quote:

Well, operating system support aswell. I intend to run some of my libraries on a 25mHz controller. I do not believe this is a case of premature optimization, as whether you use exceptions or not has a big influence on how you would design your system.

You've got that right! Exceptions, or any error-recovery strategy, needs to be built-in from the start. It is incredibly difficult to retro-fit a strategy into any significant application with satisfactory results.
quote:

but it is better than manually propagating return codes, where error-recovery logic is interspersed with program logic.
I dont really agree with you here, but fair enough..

That seems to be because you're pre-supposing a particular pattern would result from using exceptions which would favour return-codes.
quote:

An even better approach might be achievable through use of Aspects in an Aspect-Oriented language.
And this kind of reply is exactly what im looking for. Something better than exceptions and return codes. Unfortuantely your suggesting an entierly different language (right?), which is not an option for me. Any other suggestions? (can this be 'emulated' in C++?)

Oddly enough, the AOP preprocessor for Java, AspectJ, generates its code using exception mechanisms (or at least it did last time I used it). So, yes, you probably could simulate AOP. But the question is whether a simulation is of any real value. The real worth of AOP comes from what is implied in the intent of the mechanisms. Once the mechanisms become explicit in your code, you're losing some of the benefits.
quote:

If so, my initial comments apply - where did you get the above code from? Its not typical of how (good) programmers use exceptions.
I was under the impressions that this is how you use exceptions?

The general guideline for exceptions is that a well-designed strategy will involve many throws and few catches. That tends to imply that an exception will propogate up through several levels of stack before reaching a location where there is sufficient application context to be able to deal with it. Going back to file handling, the function which opens a file will probably not have sufficient context to determine what to do when the file does not exist. If you move back up a few levels, the code which requested a file to be opened will probably have more context. For example, maybe it is a custom config file - if the file does not exist, simply use a default config.

When you need to do this sort of upward propogation, use of return codes means the mechanisms are explicit and interspersed with normal flow-of-control, meaning both that you are writing more code to solve a problem and that you are obfuscating the application semantics.
quote:

People like exception mechanisms because they generate code which would otherwise be written manually. When used judiciously, they can significantly reduce the amount of code required for a program.
I am guessing you mean that this is when you are trying a whole bunch of critical things in a row which could fail that rely on another?

You can indeed use exceptions (along with the concepts of exception safety) to implement transactional semantics. But that's not really what I meant - I was hinting at the logic which propogates errors upward to a point where they can be dealt with. With return codes, this logic is explicit in your code. With exceptions, the compiler writes the code for you. Less code, less bugs.
quote:

I had a different reply to this, but It basically boils down to this: how many times after seeing one of those error messages have you been able to restore the system to a useable state?

It depends on the application. The last large C++ project I worked on, there were many ways for the user to put the system into an invalid state, and it was often the user who was in a position to best decide how to return to a valid one. Rather than just let the system enter an invalid state and leave it there, you interact with the user in order to negotiate the way back to a valid system state.
quote:

It's debatable whether a non-exceptional reporting mechanism is really an "error handling" system - it will just be reporting the normal return codes of functions.
I do consider this an error handling system, as you can use it to determine whether errors happend or not, and then deal with the situation accordingly.

I was talking about the co-existence of exceptions and return-codes. If its really an error, you will probably throw an exception, whatever's left is reported via return codes. Whether any of the return values constitute an `error' depends on perspective, which is why its debatable.
quote:

Agreed, but what else can I hope for? I dont have time to implement my whole system, get it wrong, and re-implement it again.

Why do you have to implement your whole system before making an assessment?


[edited by - SabreMan on October 14, 2003 6:25:25 AM]

Share this post


Link to post
Share on other sites
DrPizza    160
quote:
Original post by Magmai Kai Holmlor
You throw an exception if there is nothing else to do, no way the program can continue proper execution under the current conditions. Otherwise, the exception is gratuitous or the program is malformed.

But that means you''d just let any and all exceptions propagate all the way to main(), where you''d catch them, perhaps display an error message, and end the application. That seems pretty pointless; it''s barely more useful than simply calling abort() or terminate().

Share this post


Link to post
Share on other sites
Arild Fines    968
Joel Spolsky posted this yesterday: http://www.joelonsoftware.com/items/2003/10/13.html.

Personally, I think he is way off base, but Spolsky is so loud that a lot of people will listen anyway.

As some other guy said: "A silence falls across the room as I realize that Joel has written something I disagree with entirely."

--
AnkhSVN - A Visual Studio .NET Addin for the Subversion version control system.
[Project site] [Blog] [RSS] [Browse the source] [IRC channel]

Share this post


Link to post
Share on other sites
aboeing    180
re:Glass_Knife:
Im not seeing exceptions being used everywhere - most things I come across dont use exceptions.
True people generally dont like new things. I remember seeing templates for the first time and thinking they were ugly, but after seeing what they could do, I thought they were great.
Ive seen exceptions, I think they are ugly, and am unconvinced of there greatness.

re:Sabre
No. I''m trying to point out that some so-called `errors'' are not errors in the context of a particular problem, and can be reported via the normal return of a function.
That seems to be because you''re pre-supposing a particular pattern would result from using exceptions which would favour return-codes.
I was talking about the co-existence of exceptions and return-codes. If its really an error, you will probably throw an exception, whatever''s left is reported via return codes. Whether any of the return values constitute an `error'' depends on perspective, which is why its debatable.
Lets go through my pre-supposed situation again.

Make a model, with a number of textures, some of which are BMP files. One type of model (a map) on texture failure, should continue. Another type of model (a bad guy) on texture failure should fail.

Here are three different ways of doing this:

Method #1: [only use exceptions]

class BMPLoader {
public:
void LoadBMP(char *sz) {
printf("error reading %s\n",sz);
throw 1;
}
};

class Texture {
public:
void CreateFromBMP(char *sz) {
printf("CreateFromBMP\n");
BMPLoader b;
b.LoadBMP(sz);
}
};

class Model {
public:
void LoadQuakeMap() { //if error, continue

Texture t;
t.CreateFromBMP("a.bmp");
}
void LoadBadGuy() { //if error. stop.

Texture t;
t.CreateFromBMP("b.bmp");
}
};

int main() {
//method 1. use exception only

Model m;
try {
m.LoadQuakeMap();
} catch (...) {
printf("something bad has happened decide i can continue here\n");
}

try {
m.LoadBadGuy();
} catch (...) {
printf("something bad has happened decide i cant continue here\n");
return -1;
}
printf("eop.\n");
return 0;
}

I believe this is ugly, and wouldn''t want to use this.

Method #2:

int g_error=0;

class BMPLoader {
public:
void LoadBMP(char *sz) {
printf("error reading %s\n",sz);
throw 1;
}
};

class Texture {
public:
void CreateFromBMP(char *sz) {
printf("CreateFromBMP\n");
BMPLoader b;
b.LoadBMP(sz);
}
};

class Model {
public:
void LoadQuakeMap() { //if error, continue

Texture t;
try {
t.CreateFromBMP("a.bmp");
} catch (...) {
printf("warning, a texture wasnt loaded");
g_error=0;
}
}
void LoadBadGuy() { //if error. stop.

Texture t;
try {
t.CreateFromBMP("b.bmp");
} catch(...) {
printf("error, a texture wasnt loaded");
g_error=1;
}

}
};

int main() {
//method 2. use exception until you know what to do with it

Model m;

m.LoadQuakeMap();
m.LoadBadGuy();
if (g_error) {
printf("something bad has happened decide i cant continue here\n");
return -1;
}

printf("eop.\n");
return 0;
}

Nicer. (?)

Method #3:

class BaseClass {
public:
BaseClass() {
parent=NULL;
}
void SetError(int error) {
error_status=error;
if (parent!=NULL)
parent->SetError(error);
}
int error_status;
BaseClass *parent;
};


class BMPLoader: public BaseClass {
public:
void LoadBMP(char *sz) {
printf("error reading %s\n",sz);
SetError(2); return;
}
};

class Texture: public BaseClass {
public:
void CreateFromBMP(char *sz) {
printf("CreateFromBMP\n");
BMPLoader b;
b.parent=this; //done automagically as discussed earlier

b.LoadBMP(sz);
}
};

class Model:public BaseClass {
public:
void LoadQuakeMap() { //if error, continue

Texture t;
t.parent=this;
t.CreateFromBMP("a.bmp");
if (error_status)
SetError(0);
}
void LoadBadGuy() {//if error. stop.

Texture t;
t.parent=this;
t.CreateFromBMP("b.bmp");
}
};

class Main:public BaseClass {
public:
void main() {
Model m;
m.parent=this;
m.LoadQuakeMap();
m.LoadBadGuy();
if (error_status)
printf("oh no!\n");
printf("eop.\n");
}
};

int main() {
Main m;
m.main();
return 0;
}

Use own error passing system. Dont need to worry about checking both return values and exceptions.
(please keep in mind that some dodgyness(main) was done in this example to keep it simple to understand - also ''global'' errors arnt recorded with this example, but you get the idea (oh and errors are overwritten blablabla)) [keep in mind macros can be used to make this code shorter/easier-to-use]

Now we only have one method of checking for errors. developer is not responsible for propogating errors either. Best of both worlds?

This may not be a good example of where you should use exceptions, perhaps someone could suggest a different example?

With exceptions, the compiler writes the code for you. Less code, less bugs.
This is very true with regard to the above proposal, but one would hope with enough testing I would get it right. And if I then have one universal way of handling errors, this would be beneficial?

re:Fruny:OpenGL I just realised that you could do something like set warning_flag = critical_error_flag so that when you do a test for if a function failed you would always get critical errors, if thats what you wanted.. would this solve the
problem you raised then?

So, yes, you probably could simulate AOP. But the question is whether a simulation is of any real value.
so its not a good idea...

Why do you have to implement your whole system before making an assessment?
You were suggesting that without a lot of experience in using exceptions I wouldnt be able to use them properly.

re:Arild Fines:
I guess he isn''t a fan of RAII, although point #1 is good.. a safety VS lazyness tradeoff I guess..

Share this post


Link to post
Share on other sites