Consider a typical function f() somewhere on the call stack between a() and x() when the exception propagates through it. How do we want it to behave?
Well, if f() were to handle the exception it might be reasonable for it to complete its task by another method (a different algorithm, or returning a “failed” status code). But for the moment we are assuming the exception won’t be handled until we reach a(). So…
f() doesn’t complete its task.
If f() has opened a file, acquired a lock on a mutex, or (more generally)…
If f() has “allocated a resource” then the resource may not leak.If f() changes a data structure, then that structure should remains usable - no dangling pointers. Or generalising…
If f() updates the system state, then the state remains valid.
I’m going to call these conditions the “weak exception safety guarantee”. There is also a “strong exception safety guarantee” which places an additional constraint on f().
If f() terminates by propagating an exception then it has made no change to the state of the program.
There is a more formal definition of these exception safety guarantees in D Abrahams’ paper "Exception Safety in STLport" [http://www.stlport.org/doc/exception_safety.html].