The basic exception handling facilities described in the ARM allow you to write code that throws an exception object and catches it in another part of the program, further up the call chain, e.g.,

	#include <iostream.h>

	class E
	{
	public:
		E(const char* s) : msg(s) { }
		const char*	what() const { return msg; }
	private:
		const char*	msg;
	};

	void f()
	{
		throw E("exception in 'f'");
	}

	int main()
	{
		try
		{
			f();
		}
		catch (E e)
		{
			cout << "caught " << e.what() << '\n';
		}
		return 0;
	}

This level of exception handling is supported by several compilers today.


Additionally, exception specifications can be given in a function declaration, e.g.,
	void f() throw (E);

which says that f will only throw exceptions of type E, or a type derived from E. If it tries to throw something else, the function unexpected() will be called. Unfortunately, unexpected() can throw any exception, thus breaking the promise of the specification.


This loophole has been plugged and now unexpected() is only allowed to throw an appropriate exception, i.e., one that is acceptable to the exception specification that was violated. If it tries to throw anything else, the compiler will map the exception to bad_exception. This means that the compiler is now allowed to perform optimisations based on exception specifications: any called function can be assumed to throw only its declared exceptions. If bad_exception is not in the exception specification of a function which causes unexpected() to be called and such an exception is thrown, then terminate() will be called. This means that if you provide your own unexpected() handler, you should probably put bad_exception in your exception specifications.
Another loophole was that exceptions thrown by expressions in mem-initialisers could not be caught (because you could not enclose them in a try-block). This has also been fixed by allowing the following syntax:

	T::T()
	try
	: member(0)
	{
		// constructor body
	}
	catch (...)
	{
		cout << "caught exception thrown by "
		        "initialising member\n";
		terminate();
	}

The catch clause cannot return - it must throw another exception (useful for mapping exceptions between layers of an application) or it must abort in some manner.

This syntax is also allowed for ordinary functions as a convenience and such catch clauses can return to the caller.


See also The Casting Vote: Austin - March '95.