A Synergic Combination
C++ ensures that destructors of auto objects execute when an exception occurs as part of the
stack unwinding process. Take advantage of this behavior and move unconditional cleanup code into a destructor. This technique is hardly new, of course. However, the properties of local classes enable you to refine it.
You want to add cleanup code to func() which will execute unconditionally. More importantly, you want this code to execute upon leaving func(), but not sooner. To achieve these goals, you will combine the deterministic execution of auto objects' destructors and the properties of local classes. This synergic combination imitates the functionality of Java's finally.
First, define a local class before the first throw statement and add cleanup code to its destructor. This class should have only one member: a public destructor. Then, instantiate an object of this class immediately after the class's definition:
void func()
{
try
{
struct Finally
{
~Finally() { cleanup(); SMS_sysadmin("terminating");}
} finalizer;
if (something_bad) //#a1
throw X();
//#b1 otherwise continue normally
}
catch (X& x) // #a2
{
exit(1);
}
//#b2 we get here only if no exception was thrown
}
That's all! When
func() exits, either normally or due to an exception, the destructor of
finalizer will execute unconditionally and perform the necessarily process termination procedures.
The Grand Finale
You might argue that there's no need to use a local class to perform this feat: any auto object's destructor will do. However, because Finally is a local class, other programmers won't be able to create instances thereof elsewhere. More importantly, local classes have no linkage. Therefore, you can define classes with the same name in different scopes without risking name clashes:
void func()
{
class Local{} loc;//#1
}
int main()
{
class Local {} loc;//#2 OK, doesn't clash with #1
}
This property enables you to use a uniform name for such "disposable classes" in all your projects. As a security bonus, neither the local class' name nor the names of its member functions will be stored in an executable/DLL file. Consequently, crackers attempting to decompile your binaries will have a hard time indeed.