Sign in to follow this  
Decrius

A C++ library: how to handle errors / memory?

Recommended Posts

Right, I'm looking into perfecting my C++ GUI library. Error handling is not one of my strongest points and definitely needs to be improved. So, I guess I should go with exception handling and accept the code-bloat? At the moment I use a global for errors, I want my code to be reentrant, so anything else is better. Though I doubt how well exception handling works when you throw something in a thread's root function... Then, memory handling, a little more difficult. At the moment I have quite a nice system which allows users to write custom allocation / deallocation code. It also makes sure everything is allocated on the DLL, not on the EXE (or vice-versa). However, how would the application know what derived class of Memory to use? Therefore I initialize a global instance of the memory model I want to use. This will then be used throughout the code. In fact, I think this IS reentrant, since the global variable is constant, only set once (right at the start) and only ever read / never changed. Is that the "C++" way? Or should I be using the allocator class in the std namespace? And also pass these to the various containers inside the library? I choose the library to be C++, so it should be C++, not half C. Eventhough I don't like some features of C++ I still want to use it and do things as much as possible according to the "C++ standard". Only this way really teaches you C++, and else I should've gone for a C library (which is actually much easier...). Thanks for the advice.

Share this post


Link to post
Share on other sites
The C++ Way is exceptions. There's a bit of code bloat (not a huge amount, in my experience). You can't throw exceptions through threads, so you'll need to signal those sorts of errors in other ways, but they should be propagated as exceptions through the library interface.

Your memory interface sounds fine. Simpler is better. My favorite exposed allocation interface is just to allow the user to pass in a custom realloc() function pointer, with an alignment parameter if necessary. Don't worry too much about making your code look like or use the standard Allocator interface; nobody really uses it. (It's better in C++0x, apparently.)

Share this post


Link to post
Share on other sites
Thanks Sneftel!

Quote:
Original post by Sneftel
Your memory interface sounds fine. Simpler is better. My favorite exposed allocation interface is just to allow the user to pass in a custom realloc() function pointer, with an alignment parameter if necessary. Don't worry too much about making your code look like or use the standard Allocator interface; nobody really uses it. (It's better in C++0x, apparently.)


Do you store the function pointer as a global / static? Also, the dynamic containers (like std::vector's) allocate on the heap. If we have a custom memory manager (which, for instance, keeps track of memory leaks), shouldn't we also make sure the allocations done in the container are using our manager? Or shouldn't we worry about it?

Thanks.

Share this post


Link to post
Share on other sites
Quote:
Original post by Decrius
Do you store the function pointer as a global / static?
Yep. Nobody's going to run two GUI systems simultaneously with different memory managers.
Quote:
Also, the dynamic containers (like std::vector's) allocate on the heap. If we have a custom memory manager (which, for instance, keeps track of memory leaks), shouldn't we also make sure the allocations done in the container are using our manager?
Yes, certainly. So it may well make sense to make a custom allocator, internal to the library, which uses that realloc pointer. No reason to expose that, though.

Share this post


Link to post
Share on other sites
Quote:
You can't throw exceptions through threads, so you'll need to signal those sorts of errors in other ways,

Sure you can. You just need a runtime or library that implements it. (such as the one the next C++ standard, which deals with threads, mandates)

Memory and errors are central issues in C++. The answer is simple: RAII and exceptions.
They're actually two faces of the same coin, since RAII enforces basic exception-safety, and exceptions are necessary to enforce object invariants.

Share this post


Link to post
Share on other sites
Quote:
Original post by loufoque
Quote:
You can't throw exceptions through threads, so you'll need to signal those sorts of errors in other ways,

Sure you can. You just need a runtime or library that implements it. (such as the one the next C++ standard, which deals with threads, mandates)


You must tell us where you get these compilers from the future!

Share this post


Link to post
Share on other sites
Exceptions work perfectly well with threads, just not across them. Though, why would you want that in the first place?

If thread A does something that screws up and you throw an exception, it will be handled in that thread. Thread B won't know about it, but really, why would it want to? It doesn't even know what thread A is doing, so what is it supposed to add to error handling?
If another thread really needs to know (for example, to shut down the window thread if some other thread has failed beyond repair) then you can always send a notification from the exception handler. Again, this works perfectly well.

Overhead? Bloat? Well, yes... exceptions are not free. Does it matter? It depends. For a 4 kB demo it sure does, as exception handling will add a fixed overhead of at least 30-50 kB, plus a little extra depending on the amount of exception handling used. Now, the question is, do another 50 kB matter on an executable that's 3-5 MB anyway?

Share this post


Link to post
Share on other sites
Well, it's more like, does another 600kB matter on an 600kB library. That was when I did a first try. Perhaps it will be less when it's implemented better.

Also, yes, if one thread fails, the main application process should be notified. What if you have a resource loading thread (together with a network connection thread, or a display thread, w/e), and the resource loading fails. The main application sure does want to know about it.

Share this post


Link to post
Share on other sites
Quote:
Original post by Decrius
Well, it's more like, does another 600kB matter on an 600kB library. That was when I did a first try. Perhaps it will be less when it's implemented better.
In that case, you probably have 20,000 try/catch blocks? A few (2-3) large try/catch blocks placed well don't hurt so bad.

Quote:
Original post by DecriusAlso, yes, if one thread fails, the main application process should be notified. What if you have a resource loading thread (together with a network connection thread, or a display thread, w/e), and the resource loading fails. The main application sure does want to know about it.
Resource loading is normally communicated differently (message queues, lockfree linked lists, APCs, ... whatever), as you have to communicate success too. Also, failure to load a texture or a sound normally doesn't normally mandate program termination.
Though, let's assume that the display thread throws because it can't get a pixel format descriptor, which obviously limits the application's ability to continue. No problem, you can always write something like...
catch(blahexception ex)
{
if(do_handle(ex) == CANT_HANDLE)
PostThreadMessage(g_mainthread, WM_QUIT, 0, 0);
else
goto beginning;
}

Share this post


Link to post
Share on other sites

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