给出类似
的界面%feature("director") HeldBase;
%feature("smartptr") HeldBasePtr;
typedef SmartPtr<HeldBase> HeldBasePtr; // a minor wrapper around boost::shared_ptr
// Various typemaps that ensure Java-side HeldBase instances are always HeldBasePtr
class HeldBase {
public:
virtual void doSomething(int) = 0;
}
class Holder {
void hold(HeldBasePtr hb);
void release(HeldBasePtr hb);
void clear();
void process(int seconds);
}
现在一些代码实现了HeldBase,在java端做了类似的事情:
class MyHeldBase: extends HeldBase {
void doSomething(int i) { System.out.println("Hello whirled"); }
}
Holder h = new Holder();
HeldBase local = new MyHeldBase();
h.hold(new MyHeldBase());
h.hold(local);
h.process(1000000); // presumably doing something with the held things.
底层C ++层“正确”处理智能指针,因此(例如)销毁Holder(swig代理和底层C ++对象)会正确地减少底层智能指针的引用计数。
现在'本地'持有的基础工作正常,但没有在java端的引用的那个给出“null upcall”错误,大概是在一些gc导致java实例消失之后。
我注意到生成的swigTakeOwnership和swigReleaseOwnership方法,并在代码中跟踪它们以切换导演是否持有GlobalRef或GlobalWeakRef。所以我做了一些包装代码,以便调用hold(HeldBase hb)调用hb.swigReleaseOwnership()和release()调用hb.swigTakeOwnership()。看看代码似乎swigReleaseOwnership会将底层导演ref转换为GlobalRef(这样C ++层将拥有Java MyHeldBase的所有权)。反之亦然swigTakeOwnership。
不幸的是,由于无关的原因,这不起作用...我们的字体图中的某些内容使得swigTakeOwnership和swigReleaseOwnership无法调用,因为他们(认为他们)持有HeldBase *而不是HeldBasePtr *。
如果这是解决此问题的正确方法,我将尝试追踪为何没有正确生成这些方法。但我仍然觉得有一些未解决的问题(很难想到。)
例如,如何:
HeldBase local = new MyHeldBase()
Holder h1 = new Holder(); Holder h2 = new Holder();
h1.hold(local);
h2.hold(local);
h1.release(local)
local = null;
在这种情况下,对swigReleaseOwnership()的调用会发生两次,但第二次是noop。当release()调用swigTakeOwnership(使引用返回到GlobalWeakRef)时,java层再次“拥有”并且h2将获得null upcall。此外,如果需要调用swigTakeOwnership,那么Holder.clear()似乎意味着我需要添加代码来保存所有传递的java扩展控制器(此时我可以这样做来管理它们的生命周期)。
当使用带有导向器的智能指针时,“感觉”就好了,导演的C ++端应该总是只使用GlobalRef并且事情将“正常工作”但OTOH似乎是内存泄漏,因为那时C ++方面将保持Java代理生存,反之亦然。