TweetFollow Us on Twitter

C++ ExceptionsMac OS Code

Volume Number: 15 (1999)
Issue Number: 1
Column Tag: Programming Techniques

C++ Exceptions in Mac OS Code

by Steve Sisak <>

Modern C++ offers many powerful features that make code more reusable and reliable. Unfortunately, due to its UNIX roots, these often conflict with equally important features of commercial quality Mac OS code, like toolbox callbacks, multi-threading and asynchronous I/O. C++ Exception Handling is definitely an example of this. In this article, we will describe some techniques for using C++ Exceptions in commercial quality MacOS C++ code, including issues related to toolbox callbacks, library boundaries, AppleEvents, and multi-threading.

What are Exceptions?

Exception Handling isa formal mechanism for reporting and handling errors which separates the error handling code from the normal execution path. If you are unfamiliar with how C++ exceptions work, you may want to check out Chapter 14 of "The C++ Programming Language" by Bjarne Stroustrup or any of the other excellent texts on the topic.

Why are exceptions necessary?

"Exceptions cannot be ignored" - Scott Meyers

One of the problems in designing reusable code is deciding how to communicate an error that occurs deep within a library function back to someone who can handle it. There are several conventional ways for library code to report an error, including:

  • Terminating the program
  • Returning an error result
  • Setting a global error flag
  • Calling an error function
  • Performing a non-local goto (i.e. longjmp)

While terminating a program as the result of an error in input may be considered acceptable in the UNIX world, it is generally not a good idea in software you plan to ship to human users.

Returning an error or setting a flag are somewhat better, but suffer from the fact that error returns can be (and often are) ignored, either because the programmer was lazy or because a function that returns an error is called by another which has no way to report it. Both of these methods are also limited in the amount of information they can return. Return values must be meticulously passed back up the calling stack and global flags are inherently unsafe in a threaded environment because they can be modified by an error in a second thread before the first thread has had a chance to look at the error.

Calling an error handler function is reliable, but while the function may be able to log the error, it must still resort to one of the other mechanisms to handle or recover from the error.

This leaves non-local goto, which is basically how exceptions are implemented - except with formal support from the compiler. C++ exceptions extend setjmp/longjmp by guaranteeing that local variables in registers are handled properly and destructors for any local objects on the stack are called as the stack unwinds.

Because an exception is an object, it is possible for a library developer to return far more information than just an error code.

What's wrong with C++ exceptions?

In a nutshell: Lack of Standardization.

Like many aspects of C and C++, the implementation of exceptions has been left as an implementation detail to be defined by compiler vendors as they see fit. As a result, it is never safe to throw a C++ exception from a library that might be used by code compiled with a different compiler (or a different version of the same compiler, or even the same version of a compiler with different compile options).

As a result of this:

  • Exceptions must not be thrown out of a library.
  • Exceptions must not be thrown out of a toolbox callback.
  • Exceptions must not be thrown out of a thread.

Each of these cases can fail in subtly different ways:

In the first case, there is no guarantee that both compilers use compatible representations for exceptions. The C++ standard does not define a format for exceptions that is supported across multiple compilers-C++ exceptions are objects and there is no standard representation for C++ objects that is enforced across compilers. This is also why it's not feasible to export C++ classes from a shared library.

IBM's System Object Model (SOM), used in OpenDoc and Apple's Contextual Menu Manager, solves this problem for objects quite robustly (even to the extent that it is possible to mix objects and classes implemented in different languages like C++ and SmallTalk), however, there are still additional issues which would require a ""System Exception Model" "as well.

As a platform vendor, Apple could have saved us a lot of work here by specifying a "System Exception Model" that all compiler vendors would agree to implement. In fact they began to implement an Exceptions Manager as part of the PowerPC ABI but it was left unfinished the last time the developer tools group was killed and Metrowerks took over as the dominant development environment'-so we're stuck with the current state of incompatibility. Hopefully, now that Apple is working on developer tools again, we might finally see a standard.

Also, many Mac OS routines allow the programmer to specify callback routines which will be called by the toolbox during lengthy operations or to give the programmer more control than could be encoded in routine parameters. Unfortunately, because of the above limitations, it is not possible to throw an error from a callback and catch it in the code that called the original Toolbox routine.

This is because there is no way for the toolbox to clean up resources that may have been allocated before calling your function. In this case it is necessary to save off the exception data (if possible), return an error to the toolbox, and then re-throw the exception when the toolbox returns to our code. Of course, C++ provides no safe way to save off the exception currently being thrown for this purpose and RTTI does not provide enough access to extract all data from an object of unknown type, so again, we must roll our own.

There are a few toolbox managers that provide for error callback function that are not required to return. While you should be able to throw an exception from these callbacks, there are issues that you should be aware of. Specifically, some compilers implement so-called ""zero-overhead "exceptions" which use elaborate schemes of tables and tracing up the stack to restore program state without needing to explicitly save state at the beginning of a try block. Often this code gets confused by having stack frames in the calling sequence that the compiler did not generate, causing it to call terminate() on your behalf. (CodeWarrior's exceptions code also does this if you try to step over a throw from Jasik's Debugger-you can work around this by installing an empty terminate() handler.)

C and C++ have no notion of threading or accommodation for it. For instance, the C++ standard allows you to install a handler to be called if an exception is thrown and would not be caught, however you can only install one such handler per application. Further, it is technically illegal for this routine to return to its caller. So, there is no easy way to insure that an uncaught C++ exception will terminate only the thread it was thrown from rather than the entire program. (It is possible with globals and custom thread switching routines, but tricky to implement - I hope to have an example in the sample code by the time this is published)

Interactions between threads and the runtime can also rear up and bite developers in even more interesting and subtle ways: For instance, in earlier versions of CodeWarrior's runtime, the exception handler stack was kept in a linked list, the head of which was in a global variable. As a result, if exceptions were mixed with threads and the programmer did not add code to explicitly manage this compiler-generated global, the exception stacks of multiple threads would become intermingled, resulting in Really Bad Things[TM] happening if anyone actually threw an exception.

What we need is a standard way to package an exception so it can be passed across any of these boundaries and handled or re-thrown without losing information.

How did AppleEvents get in here?

As any Real Programmer[TM] knows, good Macintosh programs should be scriptable (so users can do stuff the programmer didn't think of), and recordable (so that users don't have to have intimate knowledge of AppleScript to record some actions, clean up the result and save it off for future use).

You may also know that if you want to write a scriptable and recordable application and you're starting from scratch, the easiest way to do it is to write a "factored" application - where the application is split into user interface and a server which communicate with AppleEvents.

In a past life I've written about how using AppleEvents is a convenient way to make your application multi-threaded by using an AppleEvent to pass data from the user interface to a server thread. [MacTech Dec '94]

What you may not know (thanks to the fact that it's relatively hidden in the AppleScript release notes, rather than in Inside Macintosh or a Tech Note) is that AppleScript provides a relatively robust error reporting mechanism in the form of a set of optional parameters in the reply of an AppleEvent which can specify, among other things, the error code, an explanatory string, the (AEOM) object that caused the error, and a bunch of other stuff.

Further, you may know that the AppleEvent manager provides a data structure that can hold an arbitrary collection of data (AERecord).

Putting this all together, if we define a C++ exception class which can export itself to an AERecord, we can both return extremely explicit error information a user of AppleScript (or any OSA language) and provide a standard format for exporting exception data across a library boundary. Also, since an AERecord can contain an arbitrary amount of data in any format, the programmer is free to include any information he wants in the exception - anything the recipient doesn't understand will be ignored.

Implementation Details

Following are some excerpts from an exception class and support code which do just this. Full source for a simple program using this code is provided on the conference CD. The exception mechanism is actually implemented as a pair of classes: Exception and LocationInCode and a series of macros which provide a reasonably efficient mechanism for reporting exactly where an error occurred and returning this information in the reply to an AppleEvent.

Using this mechanism, it is not only possible to throw an error across library boundaries, but also between processes or even machines.

Detection and Throwing Errors

The implementation of the Exception classes is divided between two source files: Exception.cp and LocationInCode.cp. The class Exception is the abstract representation of an exception. It has 2 subclasses: StdException and SilentException.

If you look at these two files, you'll notice that most of the functions that are involved in failure handling are implemented as macros in Exception.h which evaluate to methods of another class, LocationInCode - for instance, FailOSErr() is implemented as:

#define FailOSErr        GetLocationInCode().FailOSErr

#define GetLocationInCode()    LocationInCode(__LINE__, __FILE__)

class LocationInCode
LocationInCode(long line, const char* file) ...
void Throw(OSStatus err);
inline void    FailOSErr(OSErr err) const
if (err != noErr)
        {     // CW Seems not to be sign extending w/o cast
            Throw((OSStatus) err);

So that the expression:


Evaluates to:

LocationInCode(__LINE__, __FILE__).FailOSErr(MyFunc());

While this seems needlessly complex, there is a good reason for it, involving tradeoffs between speed, code size, and some "features" of the C++ specification.

Specifically, the obvious way to implement FailOSErr() is:

#define FailOSErr(err) if (err) Throw(err)

The problem here is that the macro FailOSErr() evaluates its argument twice. This means that, in the case of an error, MyFunc() will be called twice - clearly not what we want.

Here is one place that C++ can help us out - we can implement FailOSErr() as an inline function:

inline void FailOSErr(err)
if (err != noErr)
Throw(err, __LINE__, __FILE__);

Since C++ inline functions are guaranteed to evaluate their arguments exactly once, this solves our problem. Further, it makes it possible to have overloaded versions of FailOSErr which take different arguments, for instance a string to pass to the user, so you can write:

FailOSErr(MyFunc(), "Some Error message")

The problem is that, once you implement this and try to access the file and line information, you will discover that, thanks to the way __FILE__ and __LINE__ are defined to work, all errors are reported as occurring in Exception.h - which is clearly less than useful. You would think that, in their infinite wisdom, the C++ standards committee would have updated the way that these macros work or provided a more robust mechanism for reporting the location of an error in code, but they didn't.

The solution presented here is a compromise-by instantiating the LocationInCode class from a macro, we insure that __FILE__ and __LINE__ evaluate to a useful location in the user's code, rather than in the exceptions library. Also, by using a class, we can reduce code size by allowing the methods of TLocationInCode to call each other without losing the actual location of the error.

An added benefit of this approach is that, in the future, we could replace the implementation of LocationInCode with one using MacsBug symbols or traceback tables in the code instead of relying upon the compiler macros.

Also, note that FailOSErr() and the constructor for LocationInCode are declared inline to maximize speed, but then call an out-of-line function (Throw) to minimize code size in the failure case.

Adding Information

At any point in handling an error you can add information to an Exception by calling Exception::PutErrorParamPtr or Exception::PutErrorParamDesc. For instance, if you were in an AppleEvent handler and wanted to set the offending object displayed to the user, you could write:

// whatever
catch (Exception& exc)
exc.PutErrorParamDesc(kAEOffendingObject, whatever, false);

These routines also take a parameter to tell whether to overwrite data already in the record - this is useful to ensure that the first error that occurred is the one reported to the user.

Insuring Errors are Caught

Because it''s not safe to throw C++ exceptions across a library boundary, we need a mechanism to insure that all errors are trapped and properly reported. Unfortunately, unlike Object Pascal, we can't just call CatchFailures() to set up a handler - the code which might fail must be called from within a try block.

Also, because C++ effectively requires catch blocks to switch off of the class of the object thrown, and doesn't support the concept of 'finally' like Java, this master exception handler can end up containing quite a lot of duplicated code.

In order to minimize code size, the static method Exception::vStandardizeExceptions() provides a way to have a function called from within a block that will catch all errors and convert them to a subclass of Exception. If you plan to support other exception classes, such as the ones in the C++ standard library, you would modify this function to do the right thing.

OSStatus Exception::vStandardizeExceptions
                          (VAProc proc, va_list arg)
StdException exc(GetLocationInCode());
try                        // Call the proc
return (*proc)(arg);
catch (Exception& err)     // Exceptions are OK
throw /*err*/;
catch (char* msg)
keyErrorString, typeChar, msg, strlen(msg));
catch (long num)
catch (...)

if (LogExceptions())

throw exc;
return 0;

There are several other convenience routines, all of which call through Exception::vStandardizeExceptions(), which capture all exceptions and convert them to an OSErr or write them into an AppleEvent. For instance, the following can be used by an AppleEvent handler to catch all errors and return them in the event:

OSErr Exception::CatchAEErrors(AppleEvent* event,
                                                                            VAProc proc, ...)
va_list arg; va_start(arg, proc);
OSStatus status; 
status = vStandardizeExceptions(proc, arg);
catch (Exception& exc)
status = exc.GetOSErr();
if (event && event->dataHandle != nil)
if (status != errAEEventNotHandled)
// AppleScript has an undocumented "feature"
// where if we put an error parameter in an
// unhandled event, it reports an error rather
// than trying the system handlers.
exc.GetAEParams(*event, false));

if (status <= SHRT_MAX && status >= SHRT_MIN)
return (OSErr) status;
return eGeneralErr;

This pair of functions reports all errors to the user. (The Exceptions library allows the programmer to install a callback to report exceptions to the user. Not that here we use vStandardizeExceptions to insure that all exceptions are converted to a subclass of Exception().)

static OSStatus report_exception(va_list arg)
VA_ARG(Exception*, exc, arg);
return 0;

void Exception::ReportExceptions(VAProc proc, ...)
va_list arg; va_start(arg, proc);
vStandardizeExceptions(proc, arg));
catch (Exception& exc)
StandardizeExceptions(report_exception, &exc);
catch(Exception& exc1)
            exc1.Log();     // don't throw errors in reporting


Exception handling is both useful and practically required in robust code. However, C++ exceptions have a number of limitations which you must be aware of when you are developing code which uses operating system features not supported by the language. However, using the techniques described here, these limitations 'are not insurmountable.


  • Bjarne Stroustrup, The C++ Programming Language (Third Edition), Addison-Wesley, 1997, ISBN 2-201-88954-4
  • Scott Meyers, Effective C++ (Second Edition), Addison-Wesley, 1997, ISBN 0-201-92488-9
  • Scott Meyers, More Effective C++, Addison-Wesley, 1996, ISBN 0-201-63371-X
  • P.J. Plauger, The Draft Standard C++ Library, Prentis-Hall, 1995, ISBN 0-13-117003-1
  • James O. Coplien, Advanced C++ Programming Styles and Idioms, Addison-Wesley, 1992, ISBN 0-201-54855-0

Thanks to Miro Jurisic, Elizabeth Rehfeld, and Brett Doehr for reviewing this article.

Steve Sisak lives in Cambridge, MA, with two neurotic cats, and ten Macintoshes. Steve referees Lacrosse, plays hockey, and enjoys good beer and spicy food. Products he has worked on include The American Heritage Electronic Dictionary, PowerSecretary, Mailsmith, MacTech's Sprocket, and several others. He currently makes his living making applications scriptable and developing MacOS USB drivers.


Community Search:
MacTech Search:

Software Updates via MacUpdate

Dash 3.4.0 - Instant search and offline...
Dash is an API documentation browser and code snippet manager. Dash helps you store snippets of code, as well as instantly search and browse documentation for almost any API you might use (for a full... Read more
RapidWeaver 7.1.7 - Create template-base...
RapidWeaver is a next-generation Web design application to help you easily create professional-looking Web sites in minutes. No knowledge of complex code is required, RapidWeaver will take care of... Read more
Printopia 2.1.22 - Share Mac printers wi...
Run Printopia on your Mac to share its printers to any capable iPhone, iPad or iPod Touch. Printopia will also add virtual printers, allowing you to save print-outs to your Mac and send to apps.... Read more
SteerMouse 5.0 - Powerful third-party mo...
SteerMouse is an advanced driver for USB and Bluetooth mice. It also supports Apple Mighty Mouse very well. SteerMouse can assign various functions to buttons that Apple's software does not allow,... Read more
Arq 5.5.1 - Online backup to Google Driv...
Arq is super-easy online backup for Mac and Windows computers. Back up to your own cloud account (Amazon Cloud Drive, Google Drive, Dropbox, OneDrive, Google Cloud Storage, any S3-compatible server... Read more
Slack 2.3.0 - Collaborative communicatio...
Slack is a collaborative communication app that simplifies real-time messaging, archiving, and search for modern working teams. Version 2.3.0: Note: Now requires OS X 10.8 or later New The app... Read more
Cocktail 10.1 - General maintenance and...
Cocktail is a general purpose utility for macOS that lets you clean, repair and optimize your Mac. It is a powerful digital toolset that helps hundreds of thousands of Mac users around the world get... Read more
Firefox 49.0.2 - Fast, safe Web browser.
Firefox offers a fast, safe Web browsing experience. Browse quickly, securely, and effortlessly. With its industry-leading features, Firefox is the choice of Web development professionals and casual... Read more
Art Text 3.1 - $49.99
Art Text is graphic design software to create stunning illustrations, such as badges, flyers, logos, social headers and icons, text mockups, website graphics and buttons, picture captions, word art,... Read more
AirRadar 3.1.9 - $9.95
With AirRadar, scanning for wireless networks is now easier and more personalized! It allows you to scan for open networks and tag them as favourites or filter them out. View detailed network... Read more

Latest Forum Discussions

See All

Oh...Sir! The Insult Simulator (Games)
Oh...Sir! The Insult Simulator 1.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0 (iTunes) Description: | Read more »
WitchSpring2 (Games)
WitchSpring2 1.27 Device: iOS Universal Category: Games Price: $3.99, Version: 1.27 (iTunes) Description: This is the story of Luna, the Moonlight Witch as she sets out into the world. This is a sequel to Witch Spring. Witch Spring 2... | Read more »
4 popular apps getting a Halloween makeo...
'Tis the season for all things spooky. So much, so, in fact, that even apps are getting into the spirt of things, dressing up in costume and spreading jack o' lanterns all about the place. These updates bring frightening new character skins, scary... | Read more »
Pokémon GO celebrates Halloween with can...
The folks behind Pokémon GO have some exciting things planned for their Halloween celebration, the first in-game event since it launched back in July. Starting October 26 and ending on November 1, trainers will be running into large numbers of... | Read more »
Best Fiends Forever Guide: How to collec...
The fiendship in Seriously's hit Best Fiends has been upgraded this time around in Best Fiends Forever. It’s a fast-paced clicker with lots of color and style--kind of reminiscent of a ‘90s animal mascot game like Crash Bandicoot. The game... | Read more »
5 apps for the budding mixologist
Creating your own cocktails is something of an art form, requiring a knack for unique tastes and devising interesting combinations. It's easy to get started right in your own kitchen, though, even if you're a complete beginner. Try using one of... | Read more »
5 mobile strategy games to try when you...
Strategy enthusiasts everywhere are celebrating the release of Civilization VI this week, and so far everyone seems pretty satisfied with the first full release in the series since 2010. The series has always been about ultra-addictive gameplay... | Read more »
Popclaire talk to us about why The Virus...
Humanity has succumbed to a virus that’s spread throughout the world. Now the dead have risen with a hunger for human flesh, and all that remain are a few survivors. One of those survivors has just called you for help. That’s the plot in POPCLAIRE’... | Read more »
Oceans & Empires preview build sets...
Hugely ambitious sea battler Oceans & Empires is available to play in preview form now on Google Play - but download it quickly, as it’s setting sail away in just a few days. [Read more] | Read more »
Rusty Lake: Roots (Games)
Rusty Lake: Roots 1.1.4 Device: iOS Universal Category: Games Price: $2.99, Version: 1.1.4 (iTunes) Description: James Vanderboom's life drastically changes when he plants a special seed in the garden of the house he has inherited.... | Read more »

Price Scanner via

64GB Apple TV on sale for $159, save $40
Best Buy has the 64GB Apple TV on sale for $40 off MSRP on their online store. Choose free shipping or free local store pickup (if available). Sale price for online orders only, in-store price may... Read more
EyeQue Introduces iOS And Android Based Advan...
Affordable vision technologies developers EyeQue have announced what they claim to be the world’s most advanced intelligent vision solution, pitched as enabling anyone, anywhere to easily and... Read more
Smartwatch Market Tanks, Declining 51.6% in 2...
The worldwide smartwatch market experienced a round of growing pains in the third quarter of 2016 (3Q16), resulting in a year-over-year decline in shipment volumes. According to data from the... Read more
CAZE announces Ultra Thin Glass Screen Protec...
Hong Kong based CAZE has announced its first ultra thin glass screen protector, the Glazz Pro for iPhone 7/7 Plus. Glazz Pro is made from chemically reinforced glass with an anti-fingerprint... Read more
11-inch MacBook Airs on sale for up to $120 o...
Newegg has 11″ MacBook Airs on sale for up to $120 off MSRP. Shipping is free: - 11″ 1.6GHz/128GB MacBook Air: $799.99 $100 off MSRP - 11″ 1.6GHz/256GB MacBook Air: $979 $120 off MSRP Read more
Up to $300 off Macs, $20 off iPads with Apple...
Purchase a new Mac or iPad using Apple’s Education Store and take up to $300 off MSRP. All teachers, students, and staff of any educational institution qualify for the discount. Shipping is free, and... Read more
Apple’s Thursday “Hello Again” Event A Largel...
KGI Securities analyst Ming-Chi Kuo, who has a strong record of Apple hardware prediction accuracy, forecasts in a new note to investors released late last week that a long-overdue redo of the... Read more
12-inch Retina MacBooks on sale for $100 off...
Amazon has 2016 12″ Apple Retina MacBooks on sale for $100 off MSRP. Shipping is free: - 12″ 1.1GHz Silver Retina MacBook: $1199.99 $100 off MSRP - 12″ 1.1GHz Gold Retina MacBook: $1199.99 $100 off... Read more
Save up to $600 with Apple refurbished Mac Pr...
Apple has Certified Refurbished Mac Pros available for up to $600 off the cost of new models. An Apple one-year warranty is included with each Mac Pro, and shipping is free. The following... Read more
PixelStyle Inexpensive Photo Editor For Mac W...
PixelStyle is an all-in-one Mac Photo Editor with a huge range of high-end filters including lighting, blurs, distortions, tilt-shift, shadows, glows and so forth. PixelStyle Photo Editor for Mac... Read more

Jobs Board

*Apple* Retail - Multiple Positions - Apple,...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*Apple* Solutions Consultant - Apple (United...
# Apple Solutions Consultant Job Number: 52812872 Houston, Texas, United States Posted: Oct. 18, 2016 Weekly Hours: 40.00 **Job Summary** As an Apple Solutions Read more
Lead *Apple* Solutions Consultant - Apple (...
# Lead Apple Solutions Consultant Job Number: 52812906 Houston, Texas, United States Posted: Oct. 18, 2016 Weekly Hours: 40.00 **Job Summary** The Lead ASC is an Read more
*Apple* Retail - Multiple Positions- Towson,...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
Software Engineering Intern: Integration / QA...
Job Summary Apple is currently seeking enthusiastic interns who can work full-time for a minimum of 12-weeks between Fall 2015 and Summer 2016. Our software Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.