# Exceptions, and the stack

This topic is 4479 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I've been programming in C for a long time now (not necessarily through choice, it's what we use at work) but have frequently had to dabble with C++, often when interfacing with other peoples' or library code. But, I'm aware my understanding of C++ is not as good as it could be, and with some big deadlines out of the way I figure now's as good a time as any to fix that. Today's problem :-) is exceptions. So, I understand the concept of using them, and can write syntactically correct code to use them (though I still think it's horrifically ugly, I don't like the code that using them produces). My problem is, I just don't get what they're doing on the stack. Calling functions is easy - the code just pushes and pops various different variables and program counters onto and off the stack, no worries, easy as you like. But I don't see how exceptions could work the same way (how would you know the difference between returning from a function and throwing an exception from it?) and it confuses me. Could somebody please take a few moments to briefly explain what happens at a low level when an exception is thrown (and caught)? I'd much appreciate it!

##### Share on other sites
When an exception is thrown, the executable goes into meltdown mode. A copy of the exception is copied into a safe area, and then the stack is unwound. The destructors of all objects located on the stack are called in the reverse order of their construction until a catch block that handles that exception is found. Once the catch block is found, program execution resumes at the beginning of the catch block.

##### Share on other sites
Why do you think that the code is ugly?

One thing of which to beware is that you aren't using them like error codes, where every function call is wrapped in a try block with its own catches.

Also, be sure that you're using RAII ( which is a good idea whether or not you're using exceptions ).
// the ugly non-RAII versionvoid g() {    int *p;    try {        p = new int;        f(p); // might throw an exception        std::cout << *p << std::endl;    } catch (...) {        delete p;        throw; // rethrow the exception    }    delete p;}// the RAII versionvoid g() {    std::auto_ptr<int> p( new int );    f( p.get() ); // might throw    std::cout << *p << std::endl;    // auto_ptr's destructor deletes its pointer automatically    // when it goes out of scope, be it because of an exception    // or because the function terminates}

On the same note, std::vector takes care of new[]/delete[], std::fstream will automatically close its files, etc. Guru of the Week has lots of good articles about excetion safety and RAII and such, for more information.

##### Share on other sites
Quote:
 Original post by SiCraneA copy of the exception is copied into a safe area, and then the stack is unwound.

Could you elaborate on this "safe area" a little bit? Is it just some reserved space in the executable's data segment, or something more complex?

##### Share on other sites
It's implementation defined. It could be in the data segment of the executable or it could be dynamically allocated at the beginning of program execution. About the only restriction is that it can't be on the stack since that would cause it to be destroyed when the stack unwinds. But that's all it really is: somewhere not on the stack that you can safely stick the exception object until it's handled by something. This is why doing things like declaring an exception on the stack and throwing a pointer to the exception object isn't safe, since only the pointer will stored in the safe area, and the exception object would be destroyed during stack unwind.

##### Share on other sites
Thanks SiCrane and Me22, much appreciated. It makes a lot more sense to me now.

Me22, the code appears ugly basically because (in my limited experience) there's more typing involved, it's harder to format in a way that's easier to read, and it becomes MUCH harder to follow a path of execution. The number of exit points from a function increases and since (as you point out) the calling function isn't always the one that has to deal with the error, it means you have to go searching through many apparently unrelated code files to find out where (or indeed if) the exception gets caught.

I'm hesitant to say "I wouldn't use exceptions" for that reason because they do have uses but there was a scientist who once said something like, "just because it's beautiful doesn't mean it's right, but if it's right, it's probably going to be beautiful". Exceptions, to me, are not beautiful. (Mind you, templates, C++-style casts and namespaces aren't beautiful either, just look at all those angle brackets and colons getting in the way, but I'm quite happy to use them... Just one of those things I guess!).

I also, of course, have to be able to deal with them in other people's code, or if our team's coding standard were to include them.

##### Share on other sites
The thing is most functions should not require an explicit try/catch block. In most cases, all a function needs to do is make sure that the resources it has acquired are freed safely in the event of an exception. If you are using RAII then this is handled more or less automagically.

The exceptions (no pun intended) are functions that are intended to actually handle the exceptions. For example, recovery from a std::bad_alloc exception may be to retry an operation with a slower, but more memory friendly algorithm, or to retry after disabling certain subsystems. In that case you do need the try/catch block. However, in such a case it's probably less typing then propogating an out of memory error code up several function levels to a function that can finally handle the error.

##### Share on other sites
You can test what happens with classes that have explicit destructors. Set a break point in the destructor and see when and in what order they are called in.

##### Share on other sites
Just in case anyone was wondering why I don't like exceptions: I'm reading Herb Sutter's Exceptional C++, and Item 18 on page 60 shows a three-line function and asks "how many execution paths could there be through this function?"

There are three obvious ones, and TWENTY "invisible" ones that could be caused by exceptions. In THREE LINES.

Now, I'm not complaining about the fact that it could happen - if there are errors they need to be caught - but I don't like exceptions because I CAN'T SEE THEM HAPPEN, and it starts multiplying complexity way, way beyond most people's understanding.

I've no doubt they have their uses, but code should be as simple as possible (but no simpler, as the saying goes) and exceptions add to it's complexity.

It's a good book btw...

##### Share on other sites
Yes, but the point of writing exception safe code is so that you don't need to be able to identify each individual execution path. What matters is that you can look at a particular line of code and say 'if an exception is thrown on this line, all of the resources allocated before this line will be correctly released'.

##### Share on other sites
Quote:
 Original post by SunTzuThere are three obvious ones, and TWENTY "invisible" ones that could be caused by exceptions. In THREE LINES.

That underlines twenty possible failure points. Your three lines would be increased to over 20 to account for each return code indicating a failure. And if you don't "see" every one, instead of still having the problem dealt with, you've got a potentially stability-threatening problem.

Which is more complex, 3 lines or 20? What about when the calling code can do nothing except pass the error/exception further "upstream"?

I prefer:

void function () {    do_something(); //may throw    do_something_else(); //may throw}

to:

error_t function () {    error_t error = do_something();    if ( error != SUCCESS ) return error;    error = do_something_else();    if ( error != SUCCESS ) return error;    return SUCCESS;}

If you want things visible, use a more verbose name:

void function () {    do_something_or_throw();    do_something_else_or_throw();}

Sometimes, a return code is appropriate, e.g. for something you expect to fail. Personally, these are the names I prefer to make more verbose:

void function () {    if ( ! attempt_do_something() ) throw i_kinda_expected_this();    if ( ! attempt_do_something_else() ) throw i_kinda_expected_this();}

or:

void function () {    //kinda along the lines of "new (std::no_throw) type;"    if ( ! do_something_no_throw() ) throw i_kinda_expected_this();    if ( ! do_something_else_no_throw() ) throw i_kinda_expected_this();}

Non throwing version:

bool attempt_function () {    if ( ! attempt_do_something() ) return false;    if ( ! attempt_do_something_else() ) return false;    return true;}

If you want both available with lower mantinence, you can even do:

void function () {    if ( ! attempt_do_something() ) throw i_made_a_boo_boo();}

or:

error_t attempt_function () {    try {        function();    } catch( const std::exception & e ) {        SetErrorDescription( e.what() ); //or whatever        return I_DONT_KNOW_WHAT_HAPPENED;    }}

---

If you use RAII, not only will catching every error be cleaner (no need-to-be-explicitly-deleted objects to clean up) but you won't even need to know every potential failure point.

##### Share on other sites
Exception are a great tool for error handling.

Keep in mind: An exception is thrown on error. If you need to handle exceptions there is something wrong with that code you HAVE to deal with. If it would return an error code you still should deal with the error.

if you feel in need to do this:

try {
dosomething();
}
catch( Exception e ) {
error_handling();
}

you will get this code without exceptions:

if( dosomething() == ERROR )
error_handling();

Not realy a difference, is it?
Well one thing is a very important difference: You HAVE to handle exceptions. Not to handle them will result in a crash. If you don't handle an error code there will happen even worse: your code does something you don't expect and you might not want.

That three lines of code don't use exceptions to confuse you, but because there are errors you have to deal with. Imagine they return error codes, but you don't deal with them, what is the same afford like an unhandled exception. You can't even tell what could happen.

##### Share on other sites
Anonymous Poster: actually there's more than twice as much typing in your exception handling example than the non-exception handling example. Furthermore, you have to handle exceptions - but you could, if you so chose, do so by creating an empty catch block. Yes, that's a bad thing to do. So is ignoring error codes. (I'm not, even for one second, advocating not handling errors!).

joanusdmentia: when you get to a week before RTM and somewhere in a codebase of a million lines of code, there's at least one memory leak, scribble, AND buffer overrun... then you will see the benefit of being able to follow every code path in your head. If you can't, debugging is considerably more complicated, and in some cases approaches impossibility. Exceptions seem to simplify error handling, in certain cases, but make debugging more complex. There's always a trade-off, that's all I'm saying.