Demonstrating the Problem
An
exception-enabled program has at least two execution paths. Consider:
void func()
{
try
{
if (something_bad) //#a1
throw X();
// #b1 otherwise continue normally, then jump to #b2
}
catch (X& x)//#a2
{
exit(1);
}
//#b2 we get here only if no exception was thrown
}
When an exception occurs, control is transferred to the catch block marked #a2, after which the
exit() call terminates the program. If however no exception occurs, the section marked #b1 executes and then control is transferred to the section #b2. Thus, when certain sections of
func() execute, others don't, and vice versa. In real world code, there are more execution paths because the program may throw various types of exceptions from different locations. Additionally, there may be multiple catch blocks. The challenge is to ensure that certain operations (logging, notifying the sysadmin that the process is about to die, etc.) always take place, regardless of whether an exception has occurred.
If you're familiar with Java you will recognize that this is exactly what the finally keyword does. However, since C++ doesn't have a similar keyword, you need another mechanism to ensure the unconditional execution of cleanup code.
Introducing Local Classes
C++ has a little known feature called local classes. A local class looks like an ordinary class except that it's declared inside a function (normally, you declare classes in a namespace scope). For example:
void f()
{
class A{
public:
A() {cout<<"I'm a local class!"<<endl;}
};
}
A local class has no
linkage. Therefore, you can't refer to it from an outer scope or from other functions, blocks, and translation units:
void f()
{
class C {};
C c; //OK, in the scope of C's declaration
C * p = new C; // also OK
}
int main()
{
f();
C another_c; //error: undefined symbol 'C'
}
Local classes are instrumental in solving this problem.