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

1

8

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

Polydipsia answered 22/12, 2013 at 22:27 Comment(3)
My knowledge about C++ is much less than about Objective-C, so I might get your question completely wrong. But why would you need C++ smart pointers for Objective-C objects if you have ARC (automatic reference counting)?Sonar
ARC requires sending release messages explicitly. In C++ the equivalent decrement message is sent when the local instance variable goes out of scope (that is, the function using it returns or throws)Polydipsia
But with ARC, the compiler inserts the necessary retain/release messages into the compiled code. So from the programmers point of view, an object is released automatically if it goes out of scope.Sonar
D
14

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.

Dap answered 23/12, 2013 at 0:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.