Question

Objective-C can be mixed with c++ to some extent and can be called to each other. But Objective-C objects still are more or less manually managed, and RAII idiom is entirely absent from the language. I wonder if it is possible to manage the lifetimes of Objective-C objects with c++ smart pointers. Specially now that both boost scoped_ptr and shared_ptr have been added to the C++11 standard

Was it helpful?

Solution

But Objective-C objects still are more or less manually managed, and RAII idiom is entirely absent from the language.

I think this would seem to answer your question anyhow. Because Objective-C objects are reference counted, they already fulfill the purpose smart pointers were created for: to divorce or tie the lifetime of an object from the scope of the method it's contained in. scoped_ptrs can be recreated with autorelease pools, and shared_ptrs with -retain--release or strong references.

But saying no is boring. If you really want to mingle Objective-C and C++ like this, we'll need to first loosen the definition of "Objective-C object". The runtime recognizes anything with an isa sitting as its first member as an object, and we can take advantage of that and write a simple C++ class with a corresponding object interface so it can be messaged:

@interface CFIObject : NSObject
- (void)doSomething;
@end

struct CFIObject_cxx {
    Class isa;
public:
    CFIObject_cxx() : isa([CFIObject class]) {}
~CFIObject_cxx() { printf("I'm dying!"); }
};

@implementation CFIObject
- (void)doSomething {
    NSLog("I did something.");
}
@end

We can now instantiate an instance of our C++ object and wrap it in a smart pointer, which I'm going to purposefully split into two methods to illustrate the lifetime of the object:

void func() {
    // Instantiate a smart pointer with our fake object.
    std::unique_ptr<CFIObject_cxx> cppObj (new CFIObject_cxx());
    id obj = (__bridge id)(cppObj.get());
    // The runtime thinks we're an object.
    [obj doSomething];
    // aaaand, it's out of scope.
}

int main(int argc, const char **argv) {
    func();
    return 0;
}

As one would expect, this prints:

2013-12-22 17:23:22.681 Test[77528:303] I did something
I'm dying!

to the console.

If need be, the destructor could be outfitted to call through to -dealloc to simulate proper object destruction, but I hope you see that all of this is just wholly unnecessary, especially with ARC getting smarter with each release of CLANG.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top