Thrown exception lifecycle in C ++

Consider the following simple C ++ code:

void foo() {
    throw(my_exception());
}

void check_exc(const my_exception &exc) {
    /* Do stuff with exc */
}

void bar() {
    try {
        foo();
    } catch(const my_exception &exc) {
        check_exc(exc);
    }
}

      

In an exception handler bar

, how is it that the referenced exception exc

is still alive, seeing as it was allocated in the stack frame foo

? Hasn't that frame been unwound by the time the exception handler is triggered and any values ​​allocated there are already considered dead? Especially since I am explicitly calling another function that needs this stack space.

As a C programmer trying to learn C ++, what am I not understanding here? Where do these different meanings actually exist in memory, more precisely?

+3


source to share


4 answers


The temp created in the throw-expression is used to initialize the exception object itself, which (by specifying the standard) is "allocated in an unspecified way". This object lasts (at least) until the exception is handled, so the handler's reference to it is valid in the handler or any function called from the handler.



+7


source


Exceptions are thrown by value.

That is, the specified object is copied (possibly sliced, as with any initialization) or moved.

An exception object that you can reference with eg. a catch

the reference parameter is not allocated in the original source stack frame, but in an "undefined way".




In C ++, 11 possible ways in which objects can be allocated exclusion (inside runtime library), were limited by the requirement that exceptions objects can refer to smart pointers substantially general access std::exception_ptr

.

Sharing means that in C ++ an exception object can have a guaranteed lifetime outside of the completed exception handling.

Basically it supports passing exceptions using C code without exception code and for passing information about nested exceptions.

+3


source


The implementation will vary from platform to platform. The life cycle is more complex as you might imagine, as the throw statement starts executing on the stack frame foo ().

It is possible that the exception object gets copies and is reallocated, or the catch block can run on top of foo, but with a pointer to the bar's border to reference the column variables.

+1


source


Is he,

line

 throw(my_exception()) 

      

generates a new object of type my_exception. You can specify whatever you want (int, enums, char * or classes). Classes make more sense, of course, since you can define additional data.

After that, the entire stack will be cleared, and all recursions will complete until it hits the first try / catch block . The exception is still alive. The code in the catch block is similar to the implementation of the if / else block , slightly smarter.

amuses,

0


source







All Articles