将 shared_ptr 与 SWIG Director for Java 结合使用 [英] Using shared_ptr with SWIG Directors for Java
问题描述
我开始掌握 SWIG 的窍门,并且 SWIG 的最新版本 (v3.0) 似乎可以处理我需要的所有开箱即用的功能,包括 C++11 功能,但我遇到了在我的导演类中使用 shared_ptr 时遇到了障碍.
I'm starting to get the hang of SWIG, and the latest version(v3.0) of SWIG seems to handle just about everything I need out of the box, including C++11 features, but I have hit a snag when it comes to using shared_ptr with my director classes.
我已经能够让 shared_ptr
很好地与普通代理类一起工作,但现在在我的导演上,它似乎不受开箱即用的支持.它给了我自动生成的类型,比如 SWIGTYPE_p_std__shared_ptrT_MyDataType_t
并且正在生成一个损坏的接口,因为它使用的类型与代理类使用的类型不同.
I have been able to get shared_ptr
to work with normal proxy classes great, but now on my directors, it seems to not be supported out of the box. It is giving me the auto-generated type like SWIGTYPE_p_std__shared_ptrT_MyDataType_t
and is generating a broken interface because it isn't using the same types that the proxy classes use.
我有一个我正在尝试做的简化示例(在 swig 3.0 上使用 swig -c++ -java Test.i
运行):
I have a simplified example of what I'm trying to do (run with swig -c++ -java Test.i
on swig 3.0):
Test.i
%module(directors="1") test
%{
%}
%include <std_shared_ptr.i>
%shared_ptr(MyDataType)
class MyDataType {
public:
int value;
};
class NonDirectorClass {
public:
std::shared_ptr<MyDataType> TestMethod();
};
%feature("director") CallbackBaseClass;
class CallbackBaseClass {
public:
virtual ~CallbackBaseClass() {};
virtual std::shared_ptr<MyDataType> GetDataFromJava() {};
};
基本上我要做的是在 Java 中扩展 CallbackBaseClass
并且我希望能够传递我的 shared_ptr 包装类型.非导演类生成 shared_ptr 类型就好了.导演类代理文件正确生成,但包装器中的 SwigDirector_
方法引用了不正确的类型.
Basically what I'm going to be doing is extending the CallbackBaseClass
in Java and I want to be able to pass around my shared_ptr wrapped types. The non-director class generates the shared_ptr types just fine. The director class proxy files get generated correctly, but the SwigDirector_
methods in the wrapper reference the incorrect types.
似乎我可以通过在任何地方将 SWIGTYPE_p_std__shared_ptrT_MyDataType_t
的类型更改为 MyDataType
来手动修复文件,但我希望有更多 swig 知识的人可以回答这个问题所以这可以正确生成.
It seems like I could manually repair the files by changing the type of SWIGTYPE_p_std__shared_ptrT_MyDataType_t
to MyDataType
everywhere, but I'm hoping someone with more swig knowledge can answer the question so this can be generated correctly.
我拥有的最好线索是这里,但我仍在努力弄清楚如何正确使用这些类型映射,尤其是对于 shared_ptr
而不是基本原语.
The best clue I have is here, but I'm still trying to figure out how to correctly use these type maps, especially for shared_ptr
and not basic primitives.
更新:
文档说:
注意:目前不支持 %shared_ptr 和 Director 功能.
Note: There is currently no support for %shared_ptr and the director feature.
虽然它没有说明原因.我想知道这对于 swig 导演是否不可能,如果有充分的理由为什么不在导演中使用 shared_ptr.使用您在其他任何地方使用的相同类型似乎是有意义的.我希望答案仍然是可能的.
Though it gives no indication as to why. I'd like to know if this is an impossibility with swig directors, if there is a good reason why not to use shared_ptr in directors. It seems like it makes sense to use the same types you use everywhere else. I hope the answer is it is still possible.
推荐答案
SWIG 文档的最新版本现为:
The latest version of the SWIG documentation now reads:
对 %shared_ptr
的支持有些有限,而且导演功能和成功程度因不同的目标语言而异.请通过提供改进的补丁来帮助改进这种支持.
"There is somewhat limited support for
%shared_ptr
and the director feature and the degress of success varies among the different target languages. Please help to improve this support by providing patches with improvements."
为了使您的示例工作,我们似乎需要添加四个缺失的类型映射,directorin、directorout、javadirectorin 和 javadirectorout:
To make your example work we seem to need to add four missing typemaps, directorin, directorout, javadirectorin and javadirectorout:
%module(directors="1") test
%include <std_shared_ptr.i>
%{
#include <memory>
#include <iostream>
%}
%shared_ptr(MyDataType)
%feature("director") CallbackBaseClass;
%typemap(javadirectorin) std::shared_ptr<MyDataType> "new $typemap(jstype, MyDataType)($1,true)";
%typemap(directorin,descriptor="L$typemap(jstype, MyDataType);") std::shared_ptr<MyDataType> %{
*($&1_type*)&j$1 = new $1_type($1);
%}
%typemap(javadirectorout) std::shared_ptr<MyDataType> "$typemap(jstype, MyDataType).getCPtr($javacall)";
%typemap(directorout) std::shared_ptr<MyDataType> %{
$&1_type tmp = NULL;
*($&1_type*)&tmp = *($&1_type*)&$input;
if (!tmp) {
SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "Attempt to dereference null $1_type");
return NULL;
}
$result = *tmp;
%}
%inline %{
class MyDataType {
public:
int value;
};
class NonDirectorClass {
public:
std::shared_ptr<MyDataType> TestMethod() { return std::make_shared<MyDataType>(); }
};
class CallbackBaseClass {
public:
virtual ~CallbackBaseClass() {};
virtual std::shared_ptr<MyDataType> GetDataFromJava() = 0;
};
void frobinate(CallbackBaseClass& cb) {
std::cout << "In C++: " << cb.GetDataFromJava()->value << "\n";
}
%}
即使您只在示例中使用过directorout 情况,仍然需要directorin 类型映射才能使director_connect 中的查找成功,因为这取决于拥有正确的描述符.
Even though you only ever use the directorout case in your sample the directorin typemap is still required to make the lookup in director_connect succeed, because it depends upon having the correct descriptor.
这四种类型映射在功能上与 in、javain 和 javaout 类型映射等效,但由于它们在董事中的角色而颠倒过来.
These four typemaps are equivilent to the in, javain and javaout typemaps in functionality, but reversed because of their role in directors.
它们不够完整,无法处理所有情况,但它们适用于您的示例.描述符中的 $typemap
调用需要一个比 Ubuntu 14.04 中包含的版本更新的 SWIG 3 版本 - 在我编写它的形式中,我测试的唯一版本是从主干中检出的.您可以手动编写描述符(它只是 descriptor="LMyDataType;"
),但显然这不太通用.如上所述编写它的优点是它也可以正确处理 %rename
指令.但这也不能正确处理包,因此在这种情况下您也必须再次手动编写它.
They're not complete enough to handle all cases, but they work in your example. The $typemap
call inside the descriptor needs a version of SWIG 3 newer than the one included in Ubuntu 14.04 - in the form I wrote it the only version I tested with was checked out from the trunk. You can write the descriptor by hand (which would just be descriptor="LMyDataType;"
), but clearly that's less generic. The advantage of writing it as above is that it will handle %rename
directives correctly too. This won't handle packages properly though either so you would have to write it manually again in that case too.
我能够测试并运行该示例,我添加了以下 run.java:
I was able to test and run the example, I added the following run.java:
public class run extends CallbackBaseClass {
public MyDataType GetDataFromJava() {
MyDataType val = new MyDataType();
val.setValue(123);
return val;
}
public static void main(String[] argv) {
System.loadLibrary("test");
run r = new run();
System.out.println("In Java: " + r.GetDataFromJava().getValue());
test.frobinate(r);
}
}
并编译并运行它:
~/swig-trunk/preinst-swig -Wall -c++ -java test.i
clang++-3.6 -stdlib=libc++ -Wall -Wextra -std=c++1y test_wrap.cxx -o libtest.so -I/usr/lib/jvm/default-java/include/ -I/usr/lib/jvm/default-java/include/linux -shared -fPIC
javac run.java
LD_LIBRARY_PATH=. java run
运行时给出:
In Java: 123
In C++: 123
我猜想,对于带有 shared_ptr
+directors 的 Java 来说,正确使用描述符的微妙之处可能是阻止这种正常工作"开箱即用的主要障碍.
I would guess that in the case of Java with shared_ptr
+directors the subtleties around getting the descriptor right are probably the main blocker to having this "just work" out the box.
这篇关于将 shared_ptr 与 SWIG Director for Java 结合使用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!