Skip to main content
gamedev.net
🔒 Locked

Error checking/handling - at which level?

Started by d h k Aug 28, 2011 at 7:21 PM 5 replies 2.1k views
Original Post
d h k
d h k
So, let's say I'm writing a function for a texture manager class that checks if a certain requested texture has been loaded already, if it has it returns a pointer to that texture, if not it loads it into memory. This is something I'm sure we've all done very frequently as it's a necessity for just about every application or game that uses art assets (models, textures, sounds and so on) - but it's also a perfect example of a situation in which I find myself frequently as a programmer and that I'd love to shed some light on.

It's about error checking/handling. At which level do I want to do this (in what way)? When writing a function that loads a texture as described above, I have two choices. Either I do the error checking/handling right there, in the function itself or I delay doing so. In the former case I would have to link my error checking/handling header in the texture manager code file and then, in the function that loads the texture, check if there was an error, throw up an error report and so on. In the latter case my texture manager wouldn't know about the error handling related code at all and I'd just return a NULL instead of a pointer to texture data. This delays error handling until another 'level' of code is reached because then, when I use the texture manager in, say, my main code file, I have to do the checking there, see if my call to the function actually returned data or NULL - in which case I'd throw an error.

From my point of view, the former method means clearer code but requires links to the error handling header in lots of code files (wherever an art asset has to get loaded) while the latter approach means some ugly error checking in parts of the code where it would be more comfortable to just call the functions and assume everything worked (because the function in itself would already have thrown an error at runtime if there were any problems) but therefore is sleeker with the links between headers and code files as all the function that are loading art assets for example need no link to the error related functions, they can just return NULL.

Looking at this, I kinda prefer the former approach but I'd love to get some additional input from you all! How do you do it? Are there other alternatives, golden rules, pros or cons I haven't covered in my short evaluation there?

Thanks ahead of time!
wforl
wforl
I think its best to decouple the error reporting from the loaders, as different applications will report errors in different ways. It may be the case that you can continue the application but without certain functionality, or maybe you can just return a proxy, or finally you may have to quit the application. And then there's the question of how the errors are actually presented to the user, are they message windows, displayed on screen or logged to a file?

Because all the above could change, I'd have the loaders return 2 values, both the requested resource and an error code. Maybe something like the following.


ERROR_CODE LoadTexture( string Path, Texture** pTextureOut )
{

}



If it fails, return NULL and the reason for failure as the error code, such ERROR_INVALID_PATH or ERROR_INCOMPATIBLE_FORMAT etc etc. I tend to prefer to return a proxy resource than a NULL result, in this case you could return something like a pink texture so that it stands out, which is better than not drawing anything at all.

By using this technique, your error reporting is now decoupled, and you can report errors in different ways for each individual app you create. For example, you can wrap the above code like the following.



ERROR_CODE UI_APP_LoadTexture( string Path, Texture** pTextureOut )
{
ERROR_CODE = LoadTexture( Path, pTextureOut );

if( ERROR_CODE == FAILED )
{
DisplayError();
}
}




ERROR_CODE GAME_APP_LoadTexture( string Path, Texture** pTextureOut )
{
ERROR_CODE = LoadTexture( Path, pTextureOut );

if( ERROR_CODE == FAILED )
{
pTextureOut = GetProxyTexture();
}
}




ERROR_CODE CONSOLE_APP_LoadTexture( string Path, Texture** pTextureOut )
{
ERROR_CODE = LoadTexture( Path, pTextureOut );

if( ERROR_CODE == FAILED )
{
LogError();
}
}


So you end up with very basic error checking at the library level (assuming you've made some kind of texture loading library), and then at the application level you do custom error reporting and decisions as to what can be done should an error occur.
d h k
d h k
That's the way Direct3D does it for example, very nice. Definitely the best option I think if you're going for an engine, I'm writing a game, though, so I'm not sure if I want to be this 'general' with my functions (which would be perfect for an engine of course) - basically, I think I can afford to be more specialized. Errors are displayed in a messagebox and logged in the console window, they'll shut the game down if they were fatal too.

Am I right in thinking there's a difference in that regard between an engine and an actual game project? Or should I just go with the engine approach anyways?
wforl
wforl
I lifted the loading of textures into a library, because its something I used in many different projects. The library simply returns NULL upon failure, and the reason for failure as an error code. I then use this library in my projects, which is where I then do the custom error reporting, and decisions as to how to continue upon failure to load a resource.

In the simplest sense, and the way I see it

- A library is a collection of functionality, usually its use is very general
- An engine is a collection of libraries, but also includes the "glue" to tie them together so that they can interact
- A game project is further specialization of the functionality provided by the engine to do something specific
Magmatwister
Magmatwister

That's the way Direct3D does it for example, very nice. Definitely the best option I think if you're going for an engine, I'm writing a game, though, so I'm not sure if I want to be this 'general' with my functions (which would be perfect for an engine of course) - basically, I think I can afford to be more specialized. Errors are displayed in a messagebox and logged in the console window, they'll shut the game down if they were fatal too.

Am I right in thinking there's a difference in that regard between an engine and an actual game project? Or should I just go with the engine approach anyways?


Well, for one thing, you really shouldn't be tieing that kind of functionality to your error handling. What you want to do is make sure that the errors propagate up your hierarchy to your highest class, I.E your Framework class, which will probably just quit the program. You shouldn't have low level classes ending your game, for whatever reason. At most, you should use an exception handling system, wherein, again, the framework class is the class that does the heavy lifting. Why should an object know how to end the game? At least, this is what approach it seems you're using from what you said.
Currently trying to make a planet renderer. After many hours of work, somehow I know It'll never be complete.
Also, If I help you, please give me an ++
d h k
d h k
Oh no, that's not the case. Let me show you guys a little overview as to how it's working currently (which seems to be fine):

window.cpp/.h houses a window class that creates a window to render the game to and can also shut it down.
error.cpp/.h contains a couple of standalone functions that take an error message (std::string type) and a degree of fatality, display a messagebox, log the error to the console and then - if fatal - call the window::shutdown function.
texture_manager.cpp/.h contains a class that is responsible for loading textures. If there's something wrong with loading the texture this directly calls the error function.

This is the 'former' approach I described in the OP and seems to work fine, just means that I have a bunch of "#include " in my texture loading source files and similar. Probably unavoidable.
EJH
EJH
I prefer to handle the texture load error (or model, sound, etc.) in the Asset Manager. Then if it fails for any reason return a reference to a default texture or default model and log the error.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.