views:

1567

answers:

6

I am intrigued by how the C++ exception handling mechanism works. Specifically, where is the exception object stored and how does it propagate through several scopes until it is caught? Is it stored in some global area?

Since this could be compiler specific could somebody explain this in the context of the g++ compiler suite?

+2  A: 

Read this Article will help you

Ahmed Said
+1  A: 

You could take a look here for a detailed explanation.

It may also help to take a look at a trick used in plain C to implement some basic sort of exception handling. This entails using setjmp() and longjmp() in the following manner: the former saves the stack in order to mark the exception handler (like "catch"), while the latter is used to "throw" a value. The "thrown" value is seen as if it has been returned from a called function. The "try block" ends when setjmp() is called again or when the function returns.

Eduard - Gabriel Munteanu
+12  A: 

This is defined in 15.1 Throwing an exception of the standard.

The throw creates a temporary object.
How the memory for this temporary object is allocated is unspecified.

After creation of the temporary object control is passed to the closest handler in the call stack. unwinding the stack between throw and catch point. As the stack is unwind any stack variables are destroyed in reverse order of creation.

Unless the exception is re-thrown the temporary is destroyed at the end of the handler where it was caught.

Note: If you catch by reference the reference will refer to the temporary, If you catch by value the temporary object is copied into the value (and thus requires a copy constructor).

Advice from S.Myers (Catch by const reference).

try
{
    // do stuff
}
catch(MyException const& x)
{
}
catch(std::exception const& x)
{
}
Martin York
Something else that's unspecified is *how* the program unwinds the stack and *how* the program knows where the "closest handler" is. I'm pretty sure Borland holds a patent on one method of implementing that.
Rob Kennedy
As long as the objects are destroyed in reverse order of creation the implementation details are not important unless you are a compiler engineer.
Martin York
+4  A: 

Implementations may differ, but there are some basic ideas that follow from requirements.

The exception object itself is an object created in one function, destroyed in a caller thereof. Hence, it's typically not feasible to create the object on the stack. On the other hand, many exception objects are not very big. Ergo, one can create e.g a 32 byte buffer and overflow to heap if a bigger exception object is actually needed.

As for the actual transfer of control, two strategies exist. One is to record enough information in the stack itself to unwind the stack. This is basically a list of destructors to run and exception handlers that might catch the exception. When an exception happens, run back the stack executing those destructors until you find a matching catch.

The second strategy moves this information into tables outside the stack. Now, when an exception occurs, the call stack is used to find out which scopes are entered but not exited. Those are then looked up in the static tables to determine where the thrown exception will be handled, and which destructors run in between. This means there is less exception overhead on the stack; return addresses are needed anyway. The tables are extra data, but the compiler can put them in a demand-loaded segment of the program.

MSalters
AFAIR g++ uses the second, address-table approach, presumably for reasons of compatibility with C. Microsoft C++ compiler uses a combined approach, since its C++ exceptions are built on top of SEH (structured exception handling). In each C++ function, MSC++ creates and registers a SEH exception-handling record, which points to a table with address ranges for try-catch blocks and destructors in this particular function. throw packages a C++ exception as a SEH exception and calls RaiseException(), then SEH returns control to the C++-specific handler routine.
Anton Tykhyy
@Anton: yes, it uses the address-table approach. See my answer to another question at http://stackoverflow.com/questions/307610/how-do-exceptions-work-behind-the-scenes-in-c/307716#307716 for the details.
CesarB
A: 

@Martin York I think "unwinding the stack between throw and catch point. " should be "unwinding the stack between try and catch point. "

no that is not the case...Martins statement is fine
Yogesh Arora
+1  A: 

Refer to section 5.4 of Technical Report on C++ Performance

Yogesh Arora