Anna Koneva

Dr. Dobb's Bloggers

Interoperating between Objective-C and C++ code requires careful work -- as constructor calls vary, depending on which compiler you use.

Starting with Mac OS X 10.4 and GCC 4, you can include C++ objects as instance member variables in Objective-C classes assuming that the C++ object must be created with default constructor. How exactly the constructor works in this case, however, turns out to have some tricky aspects that can lead to confusing error messages. Let's say you have an Objective-C class and a C++ class:

If you switch to LLVM GCC from the Apple LLVM compiler (selected by default after the creation of the project), a checkbox appears in the project settings (which is not available for Clang) entitled "Call C++ Default Ctors / Dtors in Objective-C," which is the equivalent of

GCC_OBJC_CALL_CXX_CDTORS
-fobjc-call-cxx-cdtors.

If the checkbox is unchecked, compiler warnings will result:

«Type 'CppClass' has a user-defined constructor»
«C++ constructors and destructors will not be invoked for Objective-C fields»

You will find that the sequence of calls (in order from top to bottom):

In this case, our constructor (CppClass::CppClass) is not actually called, but the object is still created. The constructor generated by the compiler is called, while ours is ignored. In this case, the variable _var has a value 0 both in release and in debug modes, although member variables are not initialized by default in C++. Nevertheless, you never know if all bytes of a new object allocated this way are always zeroed in all versions of compilers.

If the checkbox is checked, then our constructor will be successfully invoked and there will be no compiler warnings.

Worthy of Note

Here is what the documentation says about this flag of GCC: -fobjc-call-cxx-cdtors

"For each Objective-C class, check if any of its instance variables is a C++ object with a non-trivial default constructor. If so, synthesize a special - (id) .cxx_construct instance method that will run non-trivial default constructors on any such instance variables, in order, and then return self. Similarly, check if any instance variable is a C++ object with a non-trivial destructor, and if so, synthesize a special - (void) .cxx_destruct method that will run all such default destructors, in reverse order.
The - (id) .cxx_construct and/or - (void) .cxx_destruct methods thusly generated will only operate on instance variables declared in the current Objective-C class, and not those inherited from superclasses. It is the responsibility of the Objective-C runtime to invoke all such methods in an object's inheritance hierarchy. The - (id) .cxx_construct methods will be invoked by the runtime immediately after a new object instance is allocated; the - (void) .cxx_destruct methods will be invoked immediately before the runtime deallocates an object instance.
As of this writing, only the NeXT runtime on OS X v10.4 and later has support for invoking the - (id) .cxx_construct and - (void) .cxx_destruct methods."

Solution

You can toggle this checkbox in the settings or switch to another compiler. If you switch to Clang, you'll find an interesting feature: Although Clang has no special option for C++ constructors/destructors, it generates correct calls for C++ constructors. Let's examine the following tests.

Case 1. Constructor (CppClass::CppClass) is not commented out. This generates no compiler warnings.

It may look like CppClass::CppClass() is called twice in a row (as opposed to GCC, where the call occurs only once). At first, I was inattentive and really thought this was the case, and I even submitted a bug report about it on Clang. However, calling an output operator from inside the constructor shows that, in fact, the constructor is actually called only once. The bug is a little different: If you put a breakpoint in the constructor, the lldb debugger stops there twice and the call stack also shows two identical calls:

GCC and Clang produce two symbols for a constructor (called C1 and C2) and one calls the other. So, breaking on the constructor sometimes breaks in both of them. I also have seen these two symbols in assembly listing.

In this case, the variable _var is also set to 0 both in release and in debug, as in the case of GCC.

As you can see, if there is a user-defined constructor CppClass::CppClass, some special function - [ObjCClass .cxx_construct] is also called, as with the GCC compiler.

Conclusion

This post concludes my series on the tricky aspects of interoperating between C/C++ and Objective-C, especially in contexts where portability across multiple compilers is needed. It's clear that the compiler writers have not adopted uniform operations to support such interoperability, so you will need to plan on spending time hunting down unexpected turns in the road. I hope this series of blog posts will be useful to you in this effort.

Anna Koneva is a computer scientist working in the Russian Federation.

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task.
However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

This month's Dr. Dobb's Journal

This month,
Dr. Dobb's Journal is devoted to mobile programming. We introduce you to Apple's new Swift programming language, discuss the perils of being the third-most-popular mobile platform, revisit SQLite on Android
, and much more!