混合使用C++和Objective-C

11
我使用C++作为应用程序的框架,使用Objective-C来制作GUI,这很好。
但是当涉及将这些代码混合在Objective-C++ (.mm文件)中时,我有一些问题:
1. 我是否可以将STL容器与Objective-C或Cocos2D对象混合使用?
例如,在Objective-C头文件中,我能做以下操作吗?
#include <vector>
#include <boost\shared_ptr.hpp>
@interface MyClass : NSObject {
  std::vector<boost::shared_ptr<CCSprite> > m_spriteList;
}

然后在 .mm 文件中,我想要执行

CCSprite* newSprite = [/* cocos2d stuff here... */];
m_spriteList.push_back(newSprite);

上面的代码有效吗?在C++中肯定有效,但是当混合使用C++、Objective-C和Cocos2D时我不确定。

2. 在Objective-C中使用C++智能指针对象进行内存管理?

当我尝试在Objective-C中使用C++代码时,我想将一个C++对象声明为Objective-C头文件中的成员变量。

假设我有一个在test.h头文件中声明的C++类:

Test{
};

在 Objective-C 的头文件中,我想要做...

#include "test.h"
#incude <boost/scoped_ptr.hpp>

#include <vector>
@interface MyClass : NSObject {
   Test* m_testObjectPtr; // (1)
   boost::scoped_ptr<Test>  m_testOjbSmartPtr; // (2)
}
在上述代码中,(2) 可以使用吗?我能在 Objective-C 中像在 C++ 代码中那样使用智能指针吗?我可以假设 MyClass 对象被销毁时 Test 类的析构函数会被调用吗?
或者,如果 (2) 在 Objective-C++ 中不可用,那么 (1) 可以使用吗?我需要在 dealloc 中手动调用 delete m_testObjectPtr 吗?

请使用正斜杠/而不是反斜杠\来分隔路径:#include <boost/shared_ptr.hpp> - kennytm
是的,谢谢。那个问题上周让我头疼了 :) 抱歉上面的代码是手动在StackOver中编写的,没有经过编译器测试... - RoundPi
2个回答

7

智能指针只能用于C++类。如果您在Objective-C类上使用它们,你将会得到编译错误或者崩溃。
您也可以使用带有指向Objective-C类的指针的容器,如下所示:

std::vector<CCSprite *> spriteList;

确保在插入到列表时保留它们,并在移除它们时释放它们。
在这两种情况下,您可以自己制作一个智能指针,像需要的那样在构造函数/析构函数/复制中调用retain和release,然后不必担心retain和release。
此外,当对象被释放时,成员C++对象的析构函数将自动调用。
一个Objective-C封装器的例子如下:

template<typename T>
struct shared_objc_object
{
    T *Object;
    shared_objc_object : Object(nil) { }
    shared_objc_object(T *Object) : Object([Object retain]) { }
    shared_objc_object(shared_objc_object &other) :
        Object([other.Object retain]) { }
    ~shared_objc_object() { [Object release]; }
    shared_objc_object &operator =(shared_objc_object &other)
    {
        [Object release];
        Object = [other.Object retain];
    }
}

您可以使用

std::vector<shared_objc_object<CCSprite *>> spriteList;
spriteList.push_back(some_sprite);

而且不需要关注保留/释放


Dani,感谢您的快速回复。您说的插入时调用retain是什么意思?您是指类似于spriteList.push_back([newSprite retain]);这样的操作吗? - RoundPi
Dani,你能回复一下我关于保留(retain)的评论吗? - RoundPi
@Gob00st:是的,无论是从向量中删除还是向量销毁时,都要执行[newSprite release] - Daniel

4

有一些问题需要注意。当将C++类作为Objective-C++对象的成员时,它们不享有与您可能习惯的相同的基于范围的生命周期。在alloc/init时,构造函数不会被调用,在release时,析构函数也不会被调用,除非您仔细使用in place new/delete或保留指针并明确使用new/delete进行管理。

此外,如果Objective-C++头文件需要与Objective-C文件共享,则不能使用任何C++结构。通过使用pimpl模式隐藏所有C++成员可以缓解这两个问题。

我能在Objective-C或Cocos2D对象中混合使用STL容器吗?

可以,因为Objective-C对象只是指向结构体的指针,所以您可以轻松地将它们存储在STL容器中,甚至可以前置声明该类型并将其传递到纯C++代码中。(请注意,C++代码实际上无法对指针执行太多操作,除非使用棘手而脆弱的代码,但您始终可以稍后将指针传回Objective-C代码以完成有用的工作。)

如何在Objective-C中使用C++智能指针对象进行内存管理?

您可以使用智能指针来管理Objective-C对象的生命周期,但需要注意它们不会调用delete(大多数C++智能指针的默认行为)。使用C++11或boost的shared_ptr,您可以提供自定义删除器;尽管现在您有两个引用计数系统。您可以改用boost::intrusive_ptr以跳过该额外开销并直接使用Objective-C的引用计数。


现在你有两个引用计数系统,你是不是指Objective-C在iOS 5中的一个引用计数,以及另一个来自智能指针?另外,请问能否提供一个简单的示例来说明boost :: intrusive_ptr和objective-c指针的使用? - RoundPi
@Gob00st - 是的,NSObject和shared_ptr都实现了引用计数,因此如果您可以利用内置的Objective-C引用计数,使用shared_ptr有点浪费,尽管它仍然可能比intrusive_ptr更容易。至于intrusive_ptr,我稍后会尝试编写一个完整的示例,但是boost的网站可能会帮助您入门(尽管intrusive_ptr的文档相当缺乏...)。 - Marc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接