Much is made of the Objective C programming language when discussing iPhone development. It’s the language of choice, many of the iPhone frameworks are written in Obj-C, etc, etc.
Coming from a background of mobile development on other platforms, I was curious about how well C++ is supported on the iPhone. BREW, Symbian and Windows Mobile all have C++ support in one shape or another, and certainly there is a ton of C++ code out there, so my thought was this: will legacy C++ code from other platforms run on iPhone?
The first thing to realize is that under the Xcode hood, Apple is using GCC (the GNU Compiler Collection) compiler for the Obj-C compilation. This is important because the GCC Obj-C compiler is in a manner of speaking also the GCC C++ compiler, with a few different command line switches. So, it seems promising – perhaps C++ support will work. But, what about run time library support? The other major platforms using the GCC tools (BREW, Symbian) have various horrible (and arguably pointless given today’s hardware) restrictions on what you can do, with various C++ “language features” simply being dropped (with various justifications). Here’s a short list of the things you typically don’t get with other mobile C++ tool chains:
1. Global static objects. Static C++ objects are regarded as a no-no for various reasons on other platforms. Both BREW and Symbian want you to reference all global application data through a pointer to allocated application heap. You’ll typically see some sort of “Applet” structure, in which the developer can embed pointers to objects that must be allocated by the application at init time. Then, there is a process of passing the pointer to ths “applet” struct around to any object that needs it, or else there will be a method provided in the platform API which will return the address of the applet struct. There’s good and bad with C++ objects defined at global scope, ordering issues, and so on; however, they can be useful, for example with smart pointers, which have the advantage of cleaning up after themselves when defined @ global scope (whereas a regular pointer would not have its destructor called as we’ll see later). Will iPhone support this?
2. Exception handling. Citing code bloat, this feature is often not supported. You can make it work on BREW w/GCC if you are prepared to do runtime lib hacking, and Symbian (last I checked) has their own non-standard variant, but the standard C++ exception handling is typically missing. Does the iPhone support this? We’re not so worried about the code size on the iPhone – the 10MB OTA AppStore limit gives plenty of room for manuever.
3. RTTI – run time type identification. This is typically not supported, the reasons given being code bloat and lack of exception support (what to do if a cast fails?). Again, does iPhone support this?
It is also important to understand how C++ code interacts with other code written in C and Obj-C. After all, having C++ support is all well and good, but it has to be practically useful, calling back and forth, etc. That said, I am going leave that aspect for a future article, and focus here on pure C++ global static objects – does the iPhone support them at all? The short answer is that, yes, it does.
Note: typically you would not really have a bunch of “loose” global static objects like this – you’d probably want to make them static class members; however, for the purposes of this article I’m simply going to define some objects at file scope, for clarity.
Here’s what I did. I started with the generic iPhone “Window Based Application” Xcode template project. To this, I then started adding C++ classes.
1. CTRL-click on Other Sources, and select Add -> New File
2. In the Mac OSX category, click on C and C++ and then select the C++ File template.
3. I gave my class the name GlobalStatic.cpp and selected ‘also create GlobalStatic.h’
This gives us empty C++ header and implementation files, the contents of which I will detail below.
Next, I followed the same three steps and made myself another C++ class called Tests (Tests.cpp/h).
OK, so the GlobalStatic class looks like this:
This is a simple class with 2 constructor overloads, a destructor and an int instance var.
The implementation looks like this:
// default constructor
GlobalStatic::GlobalStatic() : integerValue(0)
I include the C runtime stdio.h file so I can call printf(), which outputs text to the debug console (in this case). Other than that, this is a very basic class who’s main raison d’etre is to call printf() to let us know when the ctor and dtor are called. OK, so far so good.
Note: the difference between #import and #include is basically that #import has “include guards” built in, whereas #include does not. Simply put, using #import will ensure that a header file is not included twice. I’ve used #import for Objective-C headers and #include for the C++ headers, but I’ve omitted include guards in the actual headers to keep things simple.
Now, for the purposes of this exercise the file Test.h remains empty. In Tests.cpp, I define a few global static objects, as follows:
// define a global static object with default constructor
// define spme global static objects with inieger constructor
// this object will be intialized but the dtor will not be called
GlobalStatic* gsp = new GlobalStatic(3);
Then, I added two lines of code to the main.m file:
#include <stdio.h> // add this right below the #import <UIKit/UIKit.h>
And then right at the top of the main() method I added:
And that’s it. No compiler settings, nothing special, just adding the code to the project (though note that a fuller interaction between Obj-C and C++ will take a little more effort). So, what happens when you build and run this? Basically, the objects gs1, gs2 and gs3 and the pointer gsp will be created/allocated by the C++ runtime lib, and this will happen *before* the main entry to the program is called. In the debugger console (Run -> Console) you will see the following output:
When you close down the application, the destructors for the objects gs1, gs2, and gs3 will be called, and you’ll see the following output on the console:
Note! The destructor for the object pointed at by gsp is not called! This is expected, and this could potentially be a resource leak (though, in this case the runtime wil likely clean up the memory at least). It’s important to remember this though – if the GlobalStatic class had been expected to set some state in its destructor (in a database, for example), then that would never happen for that object.
There are actually many subtle (and potentially disasterous) side effects associated with the use of C++ global statics. There are ordering issues that can occur if one such object refers to another and on and on. Refer the C++ FAQ lite for details of some of the horrors (http://www.parashift.com/c++-faq-lite/ctors.html ). So, I am not holding up this technique as a panacea or even something that is highly recommended – you need to know what you are doing and even then tread very carefully. However, as s benchmark for the level of C++ support in the runtime, this is pretty good.
I will cover exceptions, RTTI and more in future articles (time permitting!). What this article has hopefully shown is that there are viable alternatives to using Obj-C on the iPhone and that if you are familiar with using C++ on pretty much any other mobile platform, it may be that the iPhone will pleasantly surprise you with what it does do, rather than by what it does not .