Advertisement

Using Exceptions

Started by June 12, 2017 04:01 PM
11 comments, last by Khatharr 7 years, 5 months ago

I researched a bit on exception handling and I have some questions for my project.

My program has vectors of my objects and it uses pop_back and push_back.

I considered everything and I was going to check for exceptions on my vector's push_back method using an ellipsis catch.

I also wanted to check the creation of my four vectors too but they have to be global because they work in other functions, so I don't think I can do that?

Does this sound acceptable?

Thank you,

Josheir

The question is, what are you going to do if the exception is triggered?

ie, it throws MemoryError on push_back. Now what?

If the answer is "we're done", there is no point in catching, since the only thing you're going to do in that case was already happening with the exception being triggered. In fact, I would argue that catching anything at this point is counter-productive. Suppose you make a programming error in the catching code. It throws an exception on it. That means you have lost the original exception at that point, ie no way to find out how it ended up in the catch-part of the code.

Secondly, if you want to continue after an exception in a useful manner, that's terribly hard. With C++ overloading, pretty much any code can throw an exception, including seemingly harmless calculations and assigments. For very specific exceptions, this is still mostly doable, as you're targeting very limited cases, so you have good knowledge on the precise conditions that can make it fail. For a very wide net, "catch everything", your exception handling code will either become unmanageable, or it isn't precise enough to really deal with every possible cause.

For beginners, I'd suggest ignore the exceptions completely. If they happen you're dead anyway, and getting useful crash information is more important. Once you get a bit more experience, start simple with catching very specific cases, and see how that works.

Personally, I am still at the "very specific case" level, and even then I prefer to make an explicit test before making a jump, ie avoid getting an exception rather than trying to catch them.

Advertisement

I'd suggest ignore the exceptions completely. If they happen you're dead anyway

What will happen than, the program will stop with a message or it will crash?

Thank you,

Josheir

What will happen than, the program will stop with a message or it will crash?

C++ typically crashes, its aim is to runs fast, under the assumption that you know what you're doing.

You can in general recover the crash location from a suitably compiled binary by means of a core-dump (at least that's what it is called in Unix, Windows likely has something similar), or by running the program from a debugger (which typically catches crash exceptions, and give you the option to inspect at that point). Both facilities need special compile-flags enabled.

What will happen than, the program will stop with a message or it will crash?

Uncaught exceptions cause std::terminate() to be called, which in turn calls a std::terminate_handler which is by default std::abort(), which raises the SIGABRT signal, causing the signal handler of the process to be called which then typically causes an abnormal termination of the process.

Anywhere on the way the implementation is free to print a message, show a helpful dialog box, pause the debugger, just crash or whatever.

blah :)

I'd strongly suggest stepping away from "ellipsis catch". This is bad, so bad I can't understand why it was even included in the language. As Alberth pointed out already, exceptions can be a tough thing to handle. Now imagine how hard it is to handle exceptions if you don't know. You don't know what failed, or in the most commonly usedantipattern, you don't know if, Errors that probably should be reported are silenced so you never see them. Again, I can't understand why this was ever included in the standard. Alas, the best thing is to stay far away from that.

On the other hand, there's nothing wrong with catching a known type if you have a hope of being able to do something meaningful. And, of course, there's nothing wrong with using exceptions in the first place. If, however, puts("Error"); exit(); is all you basically do in a handler, then better just let the program terminate with an uncaught exception! Same effect, less work, less opportunity of doing something wrong, and you don't throw away the stack info.

Ignoring exceptions altogether is nowadays an almost viable option (since in practice, you almost never see exceptions any more, used to be you'd occasionally get bad_alloc, but on multi-gigabyte 64-bit systems, that's almost only theoretical any more. Well, almost...). Ironically, there's an explicit mechanism to handle allocation failure when it occurs before it occurs. Of which I'm not sure whether to say "facepalm" or "woah, fucking cool". Maybe a bit of both.

Still, I am personally not in favour of ignoring the matter altogether from the beginning, or even disabling exceptions as a lot of people do because exceptions are part of the language (so you could as well use a different language!) and because there exist non-fatal cases where you get exceptions, and well-written code can indeed do something meaningful with it. But your code must be prepared not to break when an exception occurs (read up on "exception guarantees", you do not need all guarantees at all times (which is excruciatingly hard), but if you can guarantee at least that your program is still in a sane state at all times, exception or not, that's definitively a desirable thing).

There are idioms that you just learn to use as if they are the most natural thing when keeping in mind that exceptions exist and may occur. (such as for example copy-swap). Even when not doing everything 100% perfectly from the beginning, having the possibility of exceptions in mind finally makes your code quality better. If nothing else, you will get a better understanding of why some parts of the standard library are the way they are (for example why vector's pop_back() doesn't return the popped element -- be honest, you thought it would, didn't you!).

Advertisement
Ellipses catch is very useful when you want to do some cleanup and rethrow.
On 6/13/2017 at 4:02 AM, formerly_known_as_samoth said:

Again, I can't understand why this was ever included in the standard. Alas, the best thing is to stay far away from that.

interesting.

 

On 6/13/2017 at 4:02 AM, formerly_known_as_samoth said:

doesn't return the popped element -- be honest, you thought it would, didn't you!).

so the guarantees change behaviors.

 

Thanks everyone,

Josheir

 

 

50 minutes ago, Josheir said:

so the guarantees change behaviors.

What?

Hello to all my stalkers.

On 6/13/2017 at 2:01 AM, Josheir said:

I also wanted to check the creation of my four vectors too but they have to be global because they work in other functions, so I don't think I can do that?

Nothing HAS to be global. A good use for globals is extremely rare. If multiple functions need to access an object, use pointers/references.

On 6/13/2017 at 8:57 PM, Aardvajk said:

Ellipses catch is very useful when you want to do some cleanup and rethrow.

Or when you're calling into your C++ from another language (e.g. when writing a plugin) and want to make damn sure that you don't accidentally try to stack-unwind across a language boundary and crash the host application, instead of translating the error into a host-understandable error form.

This topic is closed to new replies.

Advertisement