uC++ EHM

Termination (Exception)

Termination is the exception-raising mechanism that unwinds the stack from the raise point to the matching handler — the faulting execution is abandoned and cannot resume where it left off.

Why call this "termination"?

Because control cannot return to the raise point. Every block between the raise block and the guarded block that catches it is terminated — local destructors run, scope-exits fire, and then the handler executes. Contrast with resumption, where the handler runs and control returns to the raise site.

Mechanism (cf. Dynamic Propagation case 3)

  • Control transfers from the raise → handler (dynamic raise, i.e., call).
  • When the handler returns, the stack is unwound (static return) to the block after the guarded block.
  • All blocks on the faulting stack from raise to handler are terminated ⇒ stack unwinding.

uC++ syntax

_Throw [ exception-type ] ;
// bare _Throw (no type) means rethrow the current exception
try {
    ...
    _Throw E();
    ...  // never reached
} catch( E & ) { ... }    // only catch clauses match _Throw

Two termination forms

The PDF distinguishes two basic forms for a non-recoverable operation:

  1. Terminate — labelled-break-like block transfer up the call stack.
  2. Retry — termination with special handler semantics: restart the guarded block. Used in Eiffel. Can be simulated with a while(true) { try { ... } catch(...) { ... } } loop, so it’s rarely supported directly.
// retry vs. simulation
char readfiles( char * files[], int N ) {
    int i = 0;
    ifstream infile;
    infile.open( files[i] );
    try {
        ... infile >> value; ...
    } retry( Eof ) {          // retry form (Eiffel-like)
        i += 1;
        infile.close();
        if ( i == N ) goto Finished;
        infile.open( files[i] );
    }
Finished: ;
}

vs. the loop-based simulation using catch( eof ) { ... break; }.

What “termination” means for the EHM

  • All objects whose lifetime ends during unwinding have their destructors run (for C++/uC++).
  • finally / _Finally blocks execute.
  • After unwinding reaches the guarded block, the handler runs and execution continues after the try.

Example

_Exception E {};
try {
    cout << "before" << endl;
    _Throw E();
    cout << "after" << endl;     // never reached — stack unwinds
} catch( E ) {
    cout << "caught" << endl;
}
cout << "done" << endl;

Output: before, caught, done.