Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Managing objective-C objects with c++ std::unique_ptr<> or std::shared_ptr<>

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

like image 449
diffeomorphism Avatar asked Dec 22 '13 22:12

diffeomorphism


1 Answers

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.

like image 104
CodaFi Avatar answered Oct 02 '22 14:10

CodaFi