Exception safety in Objective-C



Exceptions in Objective C are implemented using the C primitive:
longjmp(). Objective-C is not C++. You may have many layers of method
call between the code that raises the exception and the method that
catches it. It is very easy to write a memory leak.

Search your source code for methods that are not setters, and are not
-(void)dealloc but which call -(void)release.

A common pattern is:
MyItem *item = [[MyItem alloc] init];
[item setPart:[factory makePart]]; // calls many other things.
[myArray addObject:alteredItem];
[item release];


Now, if [factory makePart] throws an exception, the [item release] will
never get called and you'll have a memory leak. The usual fix is to get
rid of the explicit [item release] and instead create item with:

MyItem *item = [[[MyItem alloc] init] autorelease];

That does work. If -(MyItem*)makePart; throws, item will still get
released, when the autorelease pool is drained.

But that doesn't work for autorelease pools. If you are creating
autorelease pools, and something you write might call something that
might someday be maintained to throw exceptions, you must write not the
usual:

NSAutoReleasePool *pool = [[NSAutoReleasePool alloc] init];
[self doSomeWork]; // calls many other things.
[pool release];


but instead the correct:

@try {
NSAutoReleasePool *pool = [[NSAutoReleasePool alloc] init];
[self doSomeWork];
}@finally{
[pool release];
}

(Note that you don't need the @catch part.)
Written this way, and if doSomeWork calls something that throws, you
pool will get drained as the stack gets unwound on its way up to the
handler.

Lastly, If you are writing in Objective-C++, be aware that C++
exceptions and Objective-C exceptions don't mix. If your program might
ever be maintained to throw either kind, then, at the points where the
program switches from one language to the other, it must catch the inner
exception in one language, and rethrow it as the equivalent exception in
the other language. (And note as the stack is unwound the exception may
be rethrown from C++ to Objective-C and back multiple times.)

Note that any creation of an object, even convenience methods that
return autoreleased objects, calls - (id)[alloc], which in turn can
throw an NSMallocException, and be very afraid.

(In the real world, we are all in denial about this last one.)
-- David Phillip Oster

(I posted earlier version of this posting as a comment on the end of
http://www.macdevcenter.com/pub/a/mac/2007/07/31/understanding-exceptions
-and-handlers-in-cocoa.html )
.



Relevant Pages

  • Re: Cross-Platform Windows plus Mac
    ... and exceptions can't be passed easily from C++ to the Objective C ... I would imagine the Qt bindings are possible. ... Objective-C GUI code. ... something totally irrelevant about Qt bindings. ...
    (comp.sys.mac.programmer.help)
  • Re: performance
    ... efficient language and still have an inefficient system. ... > Even on these super performant silicons, some kernel code and device drivers ... > exceptions. ... > relates to the efficiency/performance of the libraries ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: Please explain the meaning of stealing a ref
    ... points of connotation as well as denotation in phrasing, and language ... clearer to _other_ readers, ... No, the use of the word 'exceptions' is anything but unreasonable, ... "Owning a reference" means being ...
    (comp.lang.python)
  • Re: performance
    ... > for kernel mode device drivers, while it's much easier to use C++ they ... > exceptions. ... ** I don't confuse language and policies, ... template libraries and no C++ exceptions. ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: [announcement] SYSAPI and SYSSVC for Windows
    ... Ada has its own concept. ... I know no language which ... But there are also numerous problems with exceptions in Ada. ... > supporting such languages as Ada. ...
    (comp.lang.ada)