Channels ▼

Anna Koneva

Dr. Dobb's Bloggers

Compiler Warnings: Calling the User-Defined Default Constructor from Objective-C++ Code

March 31, 2014

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:

The Objective-C class, ObjCClass.h, is:

#include "CppClass.h"

@interface ObjCClass : NSObject
{
    CppClass cppClass;
}

- (void)SomeObjCMethod;
@end

File ObjCClass.mm:

#import "ObjCClass.h"

@implementation ObjCClass

- (void)SomeObjCMethod
{
    cppClass.someMethod(43);
}
@end

File CppClass.h:

class CppClass
{
private:
    int _var;
public:
    CppClass();
    int someMethod(int param);
};

The C++ file, CppClass.cpp, is:

#include "CppClass.h"
#include <iostream>

using namespace std;

CppClass::CppClass()
{
    _var = 26;
}

int CppClass::someMethod(int param)
{
    cout << "param = " << param << endl << "_var = " << _var << endl;
    return param;
}

And the driver is:

#import <Foundation/Foundation.h>
#import "ObjCClass.h"

int main(int argc, const char * argv[])
{
    ObjCClass *obj = [[ObjCClass alloc] init];
    [obj SomeObjCMethod];
    [obj release];
    return 0;
}

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):

— [ObjCClass init]
— [ObjCClass SomeObjCMethod]
CppClass::someMethod(int)

What is interesting is that the program succeeds and does not crash.

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.

The sequence of calls is:

_objc_rootAllocWithZone
object_cxxConstructFromClass(objc_object*, objc_class*)
— [ObjCClass .cxx_construct]
CppClass::CppClass()
— [ObjCClass init]
— [ObjCClass SomeObjCMethod]
CppClass::someMethod(int)

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:

_objc_rootAllocWithZone
object_cxxConstructFromClass(objc_object*, objc_class*)
— [ObjCClass .cxx_construct]
CppClass::CppClass()
CppClass::CppClass()
— [ObjCClass init]
— [ObjCClass SomeObjCMethod]
CppClass::someMethod(int)

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.

Case 2. Constructor (CppClass::CppClass) is commented out. This, too, generates no compiler warnings.

The sequence of calls is:

— [ObjCClass init]
[ObjCClass SomeObjCMethod]
CppClass::someMethod(int)

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.

Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

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.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 


Video