Archived

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

ANSI2000

Exception handling

Recommended Posts

What would be the best way to create Exception handling in C++? Create exception classes internaly within the class you want to catch exceptions? Or just create them as there own...

Share this post


Link to post
Share on other sites
I''d say it depends. If you have a general type of exception that may occur anywhere in your project, then you''ll want its definition to be "global" while an exception that can only occur within a particular class should be declared as a private class.

But I agree that you should derive from std::exception or one of its derived classes and handle those at the appropriate level.

I wanna work for Microsoft!
[ GDNet Start Here | GDNet Search Tool | GDNet FAQ | MS RTFM [MSDN] | SGI STL Docs | Google! ]
Thanks to Kylotan for the idea!

Share this post


Link to post
Share on other sites
I''d go for a public nested class, or it will be hard to catch outside the class...

Pack __LINE__ and __FILE__ into the exception show-how, this provides nice & clear tracking of the source of the exception if you catch it at a higher level. Provide a method to write over the line & file, that way the you/the user can be pointed to your/their line of code that threw the exception, instead of some line buried in the exceptional class, or worse the line/file it was caught at.

I use an Error class in each of my namespaces that holds an error code, can resolve to a description, hold the line & file of the source of the expcetion, and an additional description string. Expensive, but very detailed and useful.

Something like:
m_Server.Listen(bindAddress).Where(__LINE__, __FILE__).Throw();

Listen returns a Socket::Error, Where is a method of Error, that returns a Error& to *this, which allows you to chain the calls. Throw only really throws on failure.
In my actual code I use a macro for Where(...).Throw(); so I don''t have to type all that everytime.

Letting the user decide if/when it throws is useful. If they anticipate failure, then can check error codes and retry. If they expect it to succeed, then they can make it throw. The disadtantage is they can forget to check the code or throw, then there''s an error that''s not dealt with, which was one of the thing exceptions were suppose to avoid.

If you throw C++ exceptions in your code, then it can only be used in projects that have C++ exceptions enabled. This is not permisable in a number of situations like in kernel-land, in a COM component, with a Office add-in, nor in a directshow filter. There''s probably lots more situations. IIRC, there''s some issues with throwing/catching between an app and a dll as well, though I don''t recall what''s allowed when...

Magmai Kai Holmlor

"Oh, like you''ve never written buggy code" - Lee

Share this post


Link to post
Share on other sites
Why would I want to derive from the std::exception? I was gona write my own base exception class... Unless std::exception has a whole bunch of nifty features....

Magmai __FILE__, __LINE__ Are those keywords or just flags you created in your code...

Also I will use exceptions only. Am not doing com nor amd I doing Office or direct show filters, only for my game engine... And you can catch com exceptions... Unless they are API specific, because at work with ADO I catch com exceptions...

Share this post


Link to post
Share on other sites
Derive from std::exception because it''s standard. It makes your code compatible with other code that catches standard exceptions, it makes your code readable to those who use standard exceptions, and so on. (Why am I lecturing about standards to someone who has ANSI in their username?)

Share this post


Link to post
Share on other sites
I was just wondering thats all...

I guess the STD exception also offers call stack tracing etc?

And just because it is called "standard" template library, doesnt mean it is standard and every one is using it But what ever. I don''t have a problem with it and I use it, so I will derive my exceptions from std::exception...

Share this post


Link to post
Share on other sites
The idea is, you can catch(std::exception& e) at the highest level in your code, and catch any, every, and all C++ exceptions, and everyone contains all the information specified by std::exception. So you can write error tracing code once in one spot and be done with it.

Magmai Kai Holmlor

"Oh, like you''ve never written buggy code" - Lee

Share this post


Link to post
Share on other sites
quote:
Original post by ANSI2000
Also I will use exceptions only. Am not doing com nor amd I doing Office or direct show filters, only for my game engine... And you can catch com exceptions... Unless they are API specific, because at work with ADO I catch com exceptions...


The import directive creates an exception throwing wrapper around all COM calls. All COM functions return an HRESULT. Every single one, no exceptions

If you specify raw_interfaces_only after the import directive, it will not produce a wrapper. Alternatively, if you do use the wrapper class, you can call raw_xxxx and skip the exception-baking code and get the HRESULT.

To further emulate exceptions, there''s an ISupportError (or something like that) interface which you can query/call for additional information if the COM object "excepts" (by returning E_FAIL or the like).

Magmai Kai Holmlor

"Oh, like you''ve never written buggy code" - Lee

Share this post


Link to post
Share on other sites
Welcome, btw, __LINE__, __FILE__, __DATE__, & __TIME__ are pre-defined macros, supplied by the preprocessor. There''s a lot of trash talk about how the preprocessor is evil and needs to die. The fact is, it''s indispensable. There are several excruciating useful things that you can do with macros that cannot be done with templates or other techniques.

Share this post


Link to post
Share on other sites
So bassically derive from all my exception classes from std::exception, make all unique exceptions for specific class private and use the macros within the exception calsses to output info.

Share this post


Link to post
Share on other sites
Speaking of standards,
correct me if I am wrong since I am going off a little old memory here, but by standard, doing a ''new'' should throw an exception if there is not enough memory, or the instance can not be created. Visual C++''s compiler is one of the compilers that does not like it, while several others (I think Borland is one) will take it.

I remember reading about all the ''standard'' stuff VC does not like. But then again, other compilers have standards they do not comply to either.

Share this post


Link to post
Share on other sites
That will work, you override the work method of std::exception and can dump the message where you catch it.

The problem with using __LINE__ and __FILE__ inside the exception or even inside the issuing class, is that they don''t tell you much useful information. What you _really_ want is the stack trace, you want to know what line of code blew-up and how it got there. You can gleam a useful stack-trace from both release and debug builds (when debugging you can just look at the stack-trace), in a release build it’s more complicated. You can use OS specific debug functions to get stack information, combine that with a program address map (I forget what they are really called, it''s a list of the offset to every function in your program you can make MSVC create one for both release and debug builds) Once you have the PAMs, dumping core is suddenly useful.

If you want to be portable, I think you have to do a ton of book keeping, try/catch in every method, admonish any thrown exception with the local __FILE__/__LINE__, and rethrow. I''ve been meaning to read-up on this, because the method I detailed here kinda blows. It''s more tedious work, and produces less useful information than the previous method. The OS debug stuff might take longer to get right, but once it''s done - it''s done until your OS changes. The rethrow method requires constant diligence. Someone mentioned before that Unreal used a method like this (I’ve seen it dump an unmangled stack-trace too), I think they said there’s an article about it on gamasutra.

Share this post


Link to post
Share on other sites
quote:
Original post by Taulin
Speaking of standards,
correct me if I am wrong since I am going off a little old memory here, but by standard, doing a ''new'' should throw an exception if there is not enough memory, or the instance can not be created.

I haven''t done any empirical studies, but I''ve read that VC1/4/5 return 0 as they should have, but so does 6; by the time 6 came out the standard had changed to the behavior you describe. Don''t quote me, but it may be an option to set that behavior in VC7. I saw some code for set_new_handler and even for unexpected (which MS says doesn''t work) in the new & exception headers.

If a constructor throws on new, I believe the corresponding delete is called automagically (again, no empirical studies).

And as I''ve said before, if Windows returns 0/throws on new, you may as well just call InitializeShutdownEx(SD_REBOOT|SD_FORCE) for the user, because the whole system will be unstable IF you can even manage to recover.

Share this post


Link to post
Share on other sites
quote:
Original post by Magmai Kai Holmlor
And as I''ve said before, if Windows returns 0/throws on new, you may as well just call InitializeShutdownEx(SD_REBOOT|SD_FORCE) for the user, because the whole system will be unstable IF you can even manage to recover.


I disagree. I once had a bug that caused my program to allocate 300M+ of memory. I was working in NT4 on a PC with 256MB RAM, 512MB virtual, 200MB other memory load. I was able to run the program several times, then close it (which took some time because Windows _was_ unresponsive), recompile it, and rerun it. Finally, I fixed the bug, but I still don''t know what caused it. NT ran perfectly stable for the next few days without reboot. My point is: just because you run out of memory, doesn''t mean that you can''t recover, especially on NT platforms (Not talking about Win9x here).

Share this post


Link to post
Share on other sites
You didn''t run out of memory though... If you had, either your null checking code would have kicked in, or your program would have dereferenced a null pointer. You had 768 megs available, and some 500+ odd megs in use. And NT only lasting a few days seems unstable to me

It''s advisable to set_new_handler JIC new throws you can dump a debug message (don''t allocate any memory to do it though). You can do the ''ol allocate ten megs at program start-up, deallocate it if new excepts and display a warning message, "out of memory, close programs..."

Magmai Kai Holmlor

"Oh, like you''ve never written buggy code" - Lee

Share this post


Link to post
Share on other sites
"Virtual" memory encompasses physical+page file (right?), so I has 512MB total memory, and I ran out of it. As for the few days: NT does not play games, so it was not the only OS I had installed.

Share this post


Link to post
Share on other sites
Yes, sorry I read 512meg page file, not virtual memory as you really said.

Windows will do all sorts of things to prevent an out-of-memory condition, what exactly it will do depends on the version and your setup; lazily allocating memory, and dynamically increasing the size of the page-file are two examples. Both of which could kick-in if you allocate a 300meg chunk.

It can very well still fail, but your code would know - malloc or new would return 0 instead of a valid pointer, the new_handler would be invoked, a SEH exception would be issued, etc... and the same thing would happen to any other (use-mode) process that attempts to allocate memory during this time - this is why the system becomes unstable. I suppose if everyone handled out-of-memory conditions gracefully, this wouldn't be the case. I'm just not sure how you can handle them gracefully.

Perhaps I'm misunderstanding you. Did you detect the memory allocation failure in your code and shutdown? If not, it should have excepted.


Edited by - Magmai Kai Holmlor on February 20, 2002 9:33:12 PM

Share this post


Link to post
Share on other sites
I had a weird bug and I never figured out its cause or why I was allocating 300MB of memory. It''s hard to do stuff when you have to wait 5 minutes for ''step'' command to complete . I was just saying that NT can recover from a program demanding all system memory, that''s all.

Share this post


Link to post
Share on other sites
Ok got back around to this....

How do you sub class the STL exception class?

Do I have to include any headers etc...??

Thanks

Never mind... Found it

Edited by - ANSI2000 on February 28, 2002 11:14:52 AM

Share this post


Link to post
Share on other sites