Handling Errors

Started by
11 comments, last by CTar 16 years, 11 months ago
Hiya, I'm designing the architecture for my engine, and I have a question I was hoping someone could comment on/suggest an opinion? The problem I'm having is that I'm not not entirely sure how to handle errors. My old engine had a global IEngine class, which had a ReportError() method. The idea of a central 'Engine' class seems completely redundant though - my new design comprises a DLL containing the components (Window, Renderer, etc.) and factory functions to create them, which shifts the responsibilities of the old 'Engine' class onto the client (main loop, etc.) The methods for error handling which I've considered are using return codes and using exceptions. I don't particularly like either of them in this case, as the list of return codes tends to get very long and difficult to maintain. Throwing an exception will require the client code to catch some form of custom error class or perhaps a string, and likely half of the client's code will be enclosed in try/catches, which doesn't seem optimal or very natural. I could just return true/false, and provide a GetLastError() function, similar to Windows. If anyone could give any suggestions, or what describe what has worked for them, it would be much appreciated, thanks [smile]
Advertisement
I wouldn't use a boolean return; users will want to know what is wrong, no just that it did go wrong.

If you plan to let a function fail then return a meaningful error code. If you are going to let it continue without doing what it is expected to, then set an error message, a la glGetError();
We''re sorry, but you don''t have the clearance to read this post. Please exit your browser at this time. (Code 23)
Quote:Original post by erissian
I wouldn't use a boolean return; users will want to know what is wrong, no just that it did go wrong.


Hence:

Quote:Original post by beebs1
and provide a GetLastError() function, similar to Windows.


OP: I vote for a Windows-esque GetLastError() function. That way, if all you care about is if something succeeded/failed, you get it easily, and if you want more info, it's available.
Quote:Throwing an exception will require the client code to catch some form of custom error class or perhaps a string, and likely half of the client's code will be enclosed in try/catches, which doesn't seem optimal or very natural.


No, it doesn't.

That's abuse of exceptions as return codes.

Exception means application stops. Or a subsystem stops. Crash. Bad thing(tm) happened. For example, the 3D graphics driver fails to initialize. Resource fails to load.

So exception handlers are few and far in between around critical subsystems. While testing the code I believe the overhead from not handling an error to using a std::exception was around 4% tops in extremly tight network code that needed to check for valid data some 100,000 times a second or throw an exception. But there was only one try/catch block. The total number of places where exception could be thrown (due to templates) is in hundreds (but compiler is smart about it, so this isn't a problem).

The problems with exceptions in C++ come from the way they are implemented (or incompletely define, I forget which). But exceptions are a completely valid, and IMHO much better way to handle errors than return codes for almost all cases.
Thanks for the replies - I'll go with the boolean return and a GetLastError() function.

Do you think it would be acceptable to use a global for the error code/string which will be returned by GetLastError? I'm fairly suspicious of using globals, but perhaps in this case it could be OK. I'm thinking something like the following:

// error.hint g_lastError;__declspec (dllexport) int __stdcall GetLastError();void SetLastError( int iErrorCode );


That way the client can retrieve the last error code, and the DLL code can both set and retrieve it.

Perhaps even a singleton class would be OK.

Any thoughts? Thanks again :)
Quote:Original post by beebs1
Thanks for the replies - I'll go with the boolean return and a GetLastError() function.

Do you think it would be acceptable to use a global for the error code/string which will be returned by GetLastError? I'm fairly suspicious of using globals, but perhaps in this case it could be OK. I'm thinking something like the following:

...

Perhaps even a singleton class would be OK.


Will your code be multi-threaded?

If so, how will you handle access to global variables and global error state?

Quote:
Perhaps even a singleton class would be OK.


I completely fail to see the point of a singleton here.
Antheus - good point, parts of the sound system are likely to be on a seperate thread. I'm not sure how to get around that, unless I have two functions GetLastError() and GetLastSoundError(). I guess that might need a critical section.

Rip-off: You're right of course, neither do I. Please excuse that suggestion...

Thanks for the replies.
Quote:Original post by beebs1
Antheus - good point, parts of the sound system are likely to be on a seperate thread. I'm not sure how to get around that, unless I have two functions GetLastError() and GetLastSoundError(). I guess that might need a critical section.


What about deadlocks?

How will performance be affected? You'll need to lock entire application, including rendering thread. Or, vice-versa, lock the sound thread in rendering thread.

What happens if you add other threads? GetLastXX1Error()? GetLastXX2Error()? GetLastXX3Error()?

How exactly will locking work? It's not writing to the variable that's the problem. It's locking the value for entire time during setError() and the time that getLastError() will get called. What happens, if another problem happens in between these two calls?


Disclaimer: I'm a strong advocate of exceptions (while being well aware of the problems they can cause).

Return values are very C-ish concept. They get used in certain situations, but exceptions provide a decent alternative without many of the problems.
Quote:Original post by Antheus
What about deadlocks?

How will performance be affected? You'll need to lock entire application, including rendering thread. Or, vice-versa, lock the sound thread in rendering thread.

What happens if you add other threads? GetLastXX1Error()? GetLastXX2Error()? GetLastXX3Error()?

How exactly will locking work? It's not writing to the variable that's the problem. It's locking the value for entire time during setError() and the time that getLastError() will get called. What happens, if another problem happens in between these two calls?


Ugh, I have a headache ;)

Thanks for your input Antheus. How would you handle this using exceptions? Define your own exception class (classes?) and require the client to use try/catch blocks? Or perhaps throw an error code or std::string describing the error.

I think exceptions are probably the best way of solving this, as long as I don't overdo it.

Thanks again.

This topic is closed to new replies.

Advertisement