Sunday, June 22, 2008

Tidying things up a bit ...

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.

1 comment:

ankahi said...

Reads like a book chapter, I don't know how much attention zzzzzzz...