The second thing I have been carrying over from
Symbian is a mechanism that goes
hand-in-hand with exceptions, the (infamous among beginners)
cleanup stack. Its purpose is quite simple:
insure that no memory will be leaked when exception occurs. In an environment where exceptions are used pervasively (like Symbian), the interruption of the
natural flow of execution can easily lead to
temporary objects allocated on the
heap been
orphaned, each constituting a
memory leak. The idea behind the
cleanup stack (Symbian's style) , is to allow (and actually enforce) programmers to push object on a
special stack prior to any call that could
throw an exception, or to use the standard Symbian
lingo:
leave. Once the call has been completed, the object must be popped from the
special stack. This sounds like extra work for the developer isn't it? Well, yeah it is a bit more work and a bit more careful thinking, but it is well worth the trouble when the application must run for long period of time on an system where resources are spare (iPhone anyone?).
Originally (well, last week actually ...) I had implemented my
cleanup stack as a set of C functions to be called from within a try/catch block. The problem is that thanks to the lack of
namespace and
functions overloading in
C, my functions had the
severe tendency to be ultra long. Now, I know about Apple's mantra:
"developer spend more times reading than writing code", but still who'll like to have to type this function call hundreds of times per file (yeah , OK I exaggerate a bit about the occurence of such call ...):
HZCleanupStackPopAndReleaseManyWithLastObjectL(...);
So yesterday I started re-implementing my
stack as an
Objective-C class which allow for more developer friendly code to be written, at the cost of a bit more
overhead since
messages are to be sent to the stack instead of more efficient function calls. Now, in case you did not follow one of the first page referenced on this post (actually the second one), allow me qto uickly show how the
cleanup stack is been used. Let's assume that you need to call a function that is known to leave (following Symbian coding style, the function/method name
must be
post fixed with an upper case
L):
doSomeL()
. As an experienced developer, you know that you must call this function from within a
try/catch block or from another function that is also known to throw exception. In this case, we will use a
try/catch block. Your function will be looking somewhat like this:
void doTest()
{
@try {
[HZCleanupStack windUpL];
doSomeL();
} @catch(NSException* lException) {
printf("exception occured\n");
} @finally {
[HZCleanupStack unwind];
}
}
It's contents is simple: at the start of the
try block, the
cleanup stack is winded-up (created) then the function is called. When the
try/catch block end, the stack is un-winded (destroyed). If an object was created (and placed on the
cleanup stack) in the
doSomeL()
function before it threw an exception, the un-winding of the stack in the
finally block will
release it, serving the purpose it was built for. Let's now have a look at an example of a
toublesome function:
void doSomeL()
{
HZObject* lObject[2];
HZReleaseStack* lStack = [HZCleanupStack current];
lObject[0] = [HZObject newLC];
lObject[1] = [HZObject newLC];
someFunctionL(false,lObject[1]);
[lStack popAndReleaseManyL:2 withLast:lObject[0]];
}
Here, we will assume that we have an class of object (
HZObject
) which will accept the
selector newLC
as a way of instantiating objects. The post fix
LC
indicates that the call can
throw an exception and that otherwise it will leave the created instance on the
cleanup stack. Since the function is known to potentially
leave, it is
assumed that it have been called from within a
try/catch block, thus a
cleanup stack is available, the
selector current
used on the class
HZCleanupStack
will return it to us (in fact, it will return the last winded stack for the calling thread) so that we can pop the two allocated objects. Now, what happens if this function isn't called from within a
try/catch block? Well, the creation of the first object will throw an exception and the object it-self will be
released.
If that help, I should maybe mention that the
cleanup stack concept is somewhat a kin to a
NSAutoreleasePool object with the added ability to push then pop objects at will. Maybe I'll add to this in a following post.