将Java对象传递给C++;使用Swig。。。然后回到Java C++ C++、SWIG和SWIG的指导程序,我可以传递一个继承C++类到C++的java对象。这很有效 C++ C++中,当我从C++代码中传递同一个java对象返回java时,SWIG创建一个新的Java对象来包装C++指针。问题是新对象的类型与旧对象的类型不同。我继承了java中C++类,我需要那个java对象。

将Java对象传递给C++;使用Swig。。。然后回到Java C++ C++、SWIG和SWIG的指导程序,我可以传递一个继承C++类到C++的java对象。这很有效 C++ C++中,当我从C++代码中传递同一个java对象返回java时,SWIG创建一个新的Java对象来包装C++指针。问题是新对象的类型与旧对象的类型不同。我继承了java中C++类,我需要那个java对象。,java,c++,swig,Java,C++,Swig,我为什么要这样做?我在java中有一个资源池,C++代码正在检查这些资源,然后将它们返回到池。< /P> 以下是SSCE: 这里是C++代码,它检查资源并返回它: // c_backend.cpp #include "c_backend.h" #include <stdio.h> void Server::doSomething( JobPool *jp ) { printf("In doSomthing\n"); Person *person = jp->

我为什么要这样做?我在java中有一个资源池,C++代码正在检查这些资源,然后将它们返回到池。< /P> 以下是SSCE:

这里是C++代码,它检查资源并返回它:

// c_backend.cpp
#include "c_backend.h"

#include <stdio.h>

void Server::doSomething( JobPool *jp ) {
    printf("In doSomthing\n");
    Person *person = jp->hireSomeone();
    person->doSomeWorkForMe(3);
    jp->returnToJobPool(person);
    printf("exiting doSomthing\n");
}

最后是带有基类的C++头文件,然后编译一个Mag文件:

// c_backend.h
#ifndef C_BACKEND_H
#define C_BACKEND_H

#include <stdio.h>

class Person {
    public:
        virtual ~Person() {}
        virtual void doSomeWorkForMe(int i) {
            printf("in C++ doSomeWorkForMe %i\n",i);
        }
};

class JobPool {
  public:
    virtual ~JobPool() {}
    virtual Person *hireSomeone() {
        printf("in C++ hireSomeone\n");
        return NULL;
    }
    virtual void returnToJobPool(Person *person) {
        printf("in C++ returnToJobPool\n");
    }
};


class Server {
  public:
    void doSomething( JobPool * );
};

#endif
下面是swig代码的一个片段,该代码创建了新的Java对象来替换我原来的Java对象:

public static void SwigDirector_JobPool_returnToJobPool(JobPool jself, long person) {
  jself.returnToJobPool((person == 0) ? null : new Person(person, false));
}

如果不依赖于在Java内部维护一个
HashMap
,我怎么能做到这一点呢?

您可以做到这一点,只需做一点工作,就可以不受您喜欢的约束(即不维护弱引用的映射)。事实证明,这项工作也比我原先预期的要少。我将首先讨论解决方案,然后添加一些关于我第一次尝试这样做的方式的讨论,这些方式变得太难完成

工作解决方案的高层次观点是,我们增加了三件事:

  • 一些C++代码,通过 %%扩展内部人,尝试动态转换为<代码>导演*/代码>(即SWIG导演HealCracy的一个基础)。这将保存对原始Java类(如果存在)的jobject引用。因此,我们可以简单地返回jbobject,如果强制转换失败,则返回NULL
  • < LI>一些java代码,如果不合适,将返回C++代码的结果,或者<代码> < <代码>。然后,我们可以在javadirectorin类型映射中插入来自witihin的调用,以允许从新代理“升级”到原始对象
  • 另一个简单类型映射形式的技巧是,自动将JNIEnv对象传递到#1的
    %extend
    方法中,因为它通常不能直接在那里访问,即使它可以这样公开
  • 因此,您的接口文件将变成:

    %module(directors="1") c_backend
    
    %{
    #include "c_backend.h"
    #include <iostream>
    %}
    
    %feature("director") Person;
    %feature("director") JobPool;
    // Call our extra Java code to figure out if this was really a Java object to begin with
    %typemap(javadirectorin) Person * "$jniinput == 0 ? null : new $*javaclassname($jniinput, false).swigFindRealImpl()"
    // Pass jenv into our %extend code
    %typemap(in,numinputs=0) JNIEnv *jenv "$1 = jenv;"
    %extend Person {
        // return the underlying Java object if this is a Director, or null otherwise
        jobject swigOriginalObject(JNIEnv *jenv) {
            Swig::Director *dir = dynamic_cast<Swig::Director*>($self);
            std::cerr << "Dynamic_cast: " << dir << "\n";
            if (dir) {
                return dir->swig_get_self(jenv);
            }
            return NULL;
        }
    }
    %typemap(javacode) Person %{
      // check if the C++ code finds an object and just return ourselves if it doesn't
      public Person swigFindRealImpl() {
         Object o = swigOriginalObject();
         return o != null ? ($javaclassname)o : this; 
      }
    %}
    %include "c_backend.h"
    
    它更改了
    Person
    类型,从包装器代码一直返回
    对象
    /
    作业对象
    。我的计划是,它要么是
    Person
    的实例,要么是
    java.lang.Long
    的实例,我们将根据比较实例动态决定要构造什么


    但问题是jnitype和jtypetyemaps对它们所使用的上下文没有区别。因此,
    Person
    的任何其他用法(例如构造函数、函数输入、控制器输出、控制器代码的其他位)都需要更改为使用
    Long
    对象,而不是
    Long
    原语类型。即使在变量名上匹配类型映射,它仍然无法避免过度匹配。(试试看,注意long在c_backendJNI.java中变成Person的地方)。因此,就要求非常明确的类型图命名而言,它将是丑陋的,并且仍然超过了我想要的,因此需要对其他类型图进行更具侵入性的更改。

    我想我在这里回答了基本相同的问题:-这有帮助吗?如果不是的话,我可以写一些东西来说明任何差异。事实上,这是同一个问题,解决方案对我的问题是有效的。虽然我不喜欢这个答案(尽管它有效)。我希望得到Swig的直接支持。。。事实上我希望Sigg在创建Debug实例时,将存储java对象,并在C++对象传递给java时检测并检索它。这是可能的,而且很简单。没有散列。但是,唉,现在看来是必要的。也许我们可以做一些更像你想要的事情——棘手的问题是我们要么需要通过一个JOBION,要么因为代码< >人>代码>可以是C++的类型和java的导演类型。我会有一个剧本,看看我能不能在你的限制范围内做点什么。这很快变得令人不安,因为我无法通过手术匹配“我所关心的部分”的类型图。稍后我会坚持更多,但它将变得比“用Java做”的方法更具侵入性,并且始终需要依赖
    instanceof
    dynamic\u cast
    来工作。很好,但我不同意您关于禁用RTTI的看法。RTTI不能很好地与大量模板元编程代码交互,因为所有实例都会产生RTTI开销,而没有RTTI,它们将从二进制文件中消失。这很容易会导致大量无用的RTTI数据。因此,有充分的理由让它失效。我认为,基于民间传说而非实际基准,对rtti的指控往往被夸大了。Ram很便宜,“很多MB”在除嵌入式之外的大多数情况下仍然是微不足道的,即使在现在的一些移动设备上也是如此。如果您只动态强制转换一个或两个类型,那么实际影响可能只是工作集中的一个或两个额外页面。因此,假设通过慢速链接下载不在关键路径上,我敢打赌,基准测试显示了许多其他开销,使它相形见绌。我不喜欢的是没有证据的假设,在我看到的代码库中,这种假设似乎正在减少。关于哪个解决方案的性能更好,我不想在这里猜测——在这个解决方案中有一个额外的对本机代码的调用,它涉及更多地跨越JNI边界,但是没有要维护的哈希映射,包括O(n)内存,insert/remove上没有锁定,而是用动态转换成本来交换,动态转换成本是基于类型层次结构深度而不是实例数固定的。如果存在两种解决方案切换的交叉点,我不会感到惊讶
    # Makefile
    JAVA_INCLUDE=-I/Library/Java/JavaVirtualMachines/jdk1.8.0_91.jdk/Contents/Home/include -I/Library/Java/JavaVirtualMachines/jdk1.8.0_91.jdk/Contents/Home/include/darwin
    
    all:
        c++ -c c_backend.cpp
        swig -java -c++ $(JAVA_INCLUDE) c_backend.i
        c++ $(JAVA_INCLUDE) -c c_backend_wrap.cxx
        c++ -dynamiclib -o libCBackend.jnilib *.o -framework JavaVM
        javac *.java
    
    clean:
        rm -rf *.class *.o *_wrap.cxx *_wrap.h Server.java SWIGTYPE*.java c_backend*.java JobPool.java Person.java
    
    public static void SwigDirector_JobPool_returnToJobPool(JobPool jself, long person) {
      jself.returnToJobPool((person == 0) ? null : new Person(person, false));
    }
    
    %module(directors="1") c_backend
    
    %{
    #include "c_backend.h"
    #include <iostream>
    %}
    
    %feature("director") Person;
    %feature("director") JobPool;
    // Call our extra Java code to figure out if this was really a Java object to begin with
    %typemap(javadirectorin) Person * "$jniinput == 0 ? null : new $*javaclassname($jniinput, false).swigFindRealImpl()"
    // Pass jenv into our %extend code
    %typemap(in,numinputs=0) JNIEnv *jenv "$1 = jenv;"
    %extend Person {
        // return the underlying Java object if this is a Director, or null otherwise
        jobject swigOriginalObject(JNIEnv *jenv) {
            Swig::Director *dir = dynamic_cast<Swig::Director*>($self);
            std::cerr << "Dynamic_cast: " << dir << "\n";
            if (dir) {
                return dir->swig_get_self(jenv);
            }
            return NULL;
        }
    }
    %typemap(javacode) Person %{
      // check if the C++ code finds an object and just return ourselves if it doesn't
      public Person swigFindRealImpl() {
         Object o = swigOriginalObject();
         return o != null ? ($javaclassname)o : this; 
      }
    %}
    %include "c_backend.h"
    
    //c_backend.i
    %module(directors="1") c_backend
    
    %{
    #include "c_backend.h"
    %}
    
    %feature("director") Person;
    %feature("director") JobPool;
    %typemap(jtype) Person * "Object"
    %typemap(jnitype) Person * "jobject"
    %typemap(javadirectorin) Person * "$jniinput instanceof $*javaclassname ? ($*javaclassname)$jniinput : new $*javaclassname((Long)$jniinput), false)"
    %typemap(directorin,descriptor="L/java/lang/Object;") Person * {
        SwigDirector_$1_basetype *dir = dynamic_cast<SwigDirector_$1_basetype*>($1);
        if (!dir) {
            jclass cls = JCALL1(FindClass, jenv, "java/lang/Long");
            jmid ctor = JCALL3(GetMethodID, jenv, cls, "<init>", "J(V)");
            $input = JCALL3(NewObject, jenv, cls, ctor, reinterpret_cast<jlong>($1));
        }
        else {
            $input = dir->swig_get_self(jenv);
        }
    }
    %include "c_backend.h"