2014-09-10 24 views
0

因此,首先一些背景:C++/JNI - 存储对象(jobject)在向量和数组,C++或JNI中意外发生更改问题?

我一直在努力用JNI,特别是松鼠脚本语言包装Java的C++库。当我需要将本地函数传递给Squirrel虚拟机时,问题就出现了。 Squirrel需要一个函数作为一个SQFUNCTION被定义为一个函数,它具有一个HSQUIRRELVM作为参数并返回一个SQInteger,但请记住我正在为Java封装它。我可以让C++从jobject中调用Java方法,但是我需要将这个调用包装在一个lambda函数中,以便将它实际传递给Squirrel。通常我会把[=]作为lambda捕获,所以它可以引用我的变量,但由于某些原因,我完全不确定,捕获变量会更改lambda函数的类型,并且不再将其识别为SQFUNCTION。最近我决定解决这个问题的方法是使用常量向量或数组,以便lambda可以访问它。我告诉Squirrel在vector/array中存储对象的位置,并让lambda从Squirrel获取该值以访问它。成为问题的是这样的:在正确的插槽中有一个对象,但它不是我放在那里的对象。

问题成为我不是用C++或JNI并没有什么,我搜索了告诉我这是什么样的问题,超级经验的。我试图存储对象和指向对象的指针,但是这两种方法都会得到相同的结果。我正在存储一个JSqTestFunc的实例,但代码正在检索JSqVM的实例。除了与Squirrel交互之外,这两个类共同唯一的一点是它们扩展Object,否则它们完全不相关。

我想我的问题应该是在多个部分:

  1. 这是一个C++的问题或JNI问题?
  2. 我该如何解决这个问题?

我觉得它必须是一个JNI问题,但我不能排除C++对我来说也是愚蠢的。我不熟悉JNI如何处理jobject类和对它的引用,所以也许jobject最终会在内部存储不同类的数据。我还没有发现任何与C++数组/矢量存储相关的任何问题。

C++函数如下:

static const int m_maxClosures = 8; 
static int m_closures = 0; 

static JNIEnv *m_envs[m_maxClosures]; 
static jobject m_objs[m_maxClosures]; 

JNIEXPORT void JNICALL Java_com_yourlocalfax_jsquirrel_Squirrel_sq_1newclosure_1native(JNIEnv *env, jclass c, jlong vmhandle, jobject func, jlong nfreevars) { 
    HSQUIRRELVM v = fromPointerHandleToObject<HSQUIRRELVM>(vmhandle); 

    int idx = m_closures; 

    printf("Creating number %d closure of %d", idx, m_maxClosures); 

    m_closures++; 

    m_envs[idx] = env; 
    m_objs[idx] = func; 

    sq_pushinteger(v, idx); 

    JNIEnv *e = m_envs[idx]; 
    jobject o = m_objs[idx]; 

    jobject clsObj = e->CallObjectMethod(o, e->GetMethodID(e->GetObjectClass(o), "getClass", "()Ljava/lang/Class;")); 
    jstring strObj = (jstring)e->CallObjectMethod(clsObj, e->GetMethodID(e->GetObjectClass(clsObj), "getName", "()Ljava/lang/String;")); 

    const char* str = e->GetStringUTFChars(strObj, NULL); 
    printf("\nInitial calling class is: %s\n", str); 
    e->ReleaseStringUTFChars(strObj, str); 

    SQFUNCTION f = [](HSQUIRRELVM v) { 
     print_args(v); 
     squirrel_stack_trace(v); 

     SQInteger i; 

     sq_pushinteger(v, 0); // Push the index in the table TO GET 
     sq_get(v, 1); // Push the index of the actual table 
     sq_getinteger(v, -1, &i); // Get the newly pushed value (integer) 
     //sq_getinteger(v, 2, &i); 
     printf("Location Id is %d of %d", i, m_maxClosures); 

     JNIEnv *e = m_envs[i]; 
     jobject o = m_objs[i]; 

     jobject clsObj = e->CallObjectMethod(o, e->GetMethodID(e->GetObjectClass(o), "getClass", "()Ljava/lang/Class;")); 
     jstring strObj = (jstring)e->CallObjectMethod(clsObj, e->GetMethodID(e->GetObjectClass(clsObj), "getName", "()Ljava/lang/String;")); 

     const char* str = e->GetStringUTFChars(strObj, NULL); 
     printf("\nCalling class is: %s\n", str); 
     e->ReleaseStringUTFChars(strObj, str); 

     jclass cls = e->GetObjectClass(o); 
     jmethodID m = e->GetMethodID(cls, "function", "(Lcom/yourlocalfax/jsquirrel/JSqVM;)I"); 
     //sq_pushinteger(v, e->CallIntMethod(o, m)); 
     return (SQInteger)0; 
    }; 

    sq_newclosure(v, f, nfreevars + 1); 
} 

我应该提到的是,fromPointerHandleToObject还没有让我失望的是,我用它在所有其他函数调用,并屡试不爽。如果你仍然想看看这个代码,我可以发布它。

和输出是这样的:

Creating number 0 closure of 8 
Initial calling class is: com.yourlocalfax.jsquirrel.test.JSqTestFunc 
Location Id is 0 of 8 
Calling class is: com.yourlocalfax.jsquirrel.JSqVM 

正如可以看到,在检索时在jobject数组的索引0存储JSqTestFunc最初而是JSqVM

任何帮助可言,这样做的甚至是不同的方法,因为我已经花的时间太长和太多的精力试图解决这一问题是非常赞赏。谢谢!

回答

2

我继续发布该研究后更重,并意识到它的确是在与本地和全球引用JNI端的问题。我所要做的只是env->NewGlobalRef(object);,然后将对象存储在数组中。这解决了它。

我要留下这个问题并回答以防万一以后帮助任何人。

相关问题