Reputation: 105
I am trying to create a c++ class and hold its objects into an array, and reference those c++ objects from java using JNI, since JNI does not provide any mechanism to hold any non primitive type of objects into java.
I have implemented the code as mentioned below but the output is showing me as if multiple objects have got created and i am also receiving a heap error on the second call to create a new native object.
Can anyone look into this?
thanks
Codes:
Java class(The function for loading library dll has been defined in LibObj):
package org.jnp.pkg004;
import org.jnp.libloader.LibObj;
public class PureCppObjFactory extends LibObj {
private long cppobjlstsz;
public PureCppObjFactory() {
super();
cppobjlstsz=0;
}
public native void newCppObj();
public native void PrintCppObjDetails(long cppobjlstindex);
}
C++ library code:
#include "stdafx.h"
#include "stdlib.h"
#include <iostream>
#include <iomanip>
#include <stdio.h>
using namespace std;
#include "org_jnp_pkg004_PureCppObjFactory.h"
class NativeObjClass
{
private:
int num_ran;
int obj_num;
public:
static int obj_cnt;
NativeObjClass()
{
obj_cnt++;
obj_num=obj_cnt;
num_ran=rand();
cout<<"Native Object number "<<setfill('0')<<setw(5)<<obj_cnt<<" Random number:"<<num_ran<<endl;
}
int get_obj_num()
{
return obj_num;
}
int get_num_ran()
{
return num_ran;
}
};
int NativeObjClass::obj_cnt=0;
NativeObjClass *nobj_lst;
long nobj_lst_size=0;
JNIEXPORT void JNICALL Java_org_jnp_pkg004_PureCppObjFactory_newCppObj
(JNIEnv *env, jobject obj)
{
jclass thisCls = env->GetObjectClass(obj);
jfieldID fid=env->GetFieldID(thisCls,"cppobjlstsz","J");
NativeObjClass nobj;
jlong java_lst_sz=env->GetLongField(obj,fid);
NativeObjClass *temp_nobj_lst;
temp_nobj_lst=new NativeObjClass[nobj_lst_size];
if(nobj_lst_size>0)
{
memmove(temp_nobj_lst,nobj_lst,nobj_lst_size);
delete nobj_lst;
}
nobj_lst_size++;
nobj_lst=new NativeObjClass[nobj_lst_size];
if(nobj_lst_size>1)
{
memmove(nobj_lst,temp_nobj_lst,nobj_lst_size);
delete temp_nobj_lst;
}
nobj_lst[nobj_lst_size]=nobj;
java_lst_sz++;
env->SetLongField(obj,fid,java_lst_sz);
}
JNIEXPORT void JNICALL Java_org_jnp_pkg004_PureCppObjFactory_PrintCppObjDetails
(JNIEnv *env, jobject obj, jlong indx)
{
NativeObjClass nobj=nobj_lst[indx];
cout<<"Retrieved Native Object number "<<setfill('0')<<setw(5)<<nobj.get_obj_num()<<" Random number:"<<nobj.get_num_ran()<<endl;
}
Class containing main:
package test.jnp.pkg004;
import org.jnp.pkg004.PureCppObjFactory;
public class PureCppObjFactoryTest {
public static void main(String[] args) {
PureCppObjFactory pcf=new PureCppObjFactory();
pcf.newCppObj();
pcf.PrintCppObjDetails(0);
pcf.newCppObj();
//pcf.newCppObj();
}
}
Output:
Native Object number 00001 Random number:41
Native Object number 00002 Random number:18467
Retrieved Native Object number 00002 Random number:18467
Native Object number 00003 Random number:6334
Native Object number 00004 Random number:26500
Also getting a heap error popup after this code executes
Upvotes: 5
Views: 2517
Reputation: 91270
Ok, here's a list of issues seen at first glance:
using namespace std;
is bad formstatic int obj_cnt;
isn't threadsafeNativeObjClass *nobj_lst;
should be a static memberNativeObjClass *nobj_lst;
should be a std::vectorlong nobj_lst_size=0;
should be a static memberlong nobj_lst_size=0;
should be of type size_t
NativeObjClass nobj;
creates an object - it's not just a referencenobj_lst=(NativeObjClass*)calloc(nobj_lst_size,sizeof(NativeObjClass));
is just plain wrong. Use new[]
if you have to use your manually managed array, but a std::vector
would still be betternobj_lst[nobj_lst_size-1]=nobj
copies the object you createdNativeObjClass nobj=nobj_lst[indx];
makes a pointless copy of your array objectConsider this approach instead. Note that the below code has not been tested or even compiled, it's just to display the idea.
public class CppObject {
private long handle;
public CppObject() {
handle = createNativeObject();
}
public void cleanup() {
deleteNativeObject(handle);
handle = 0;
}
private static native long createNativeObject();
private static native void deleteNativeObject(long handle);
private static native void printObjectDetails(long handle);
public void PrintObjDetails() {
printObjectDetails(handle);
}
}
JNIEXPORT jlong JNICALL whatever_createNativeObject(JNIEnv *env, jobject obj) {
return reinterpret_cast<jlong>(new CppObject());
}
JNIEXPORT void JNICALL whatever_deleteNativeObject(JNIEnv *env, jobject obj, jlong handle) {
delete reinterpret_cast<CppObject *>(handle);
}
JNIEXPORT void JNICALL printObjectDetails(JNIEnv *env, jobject obj, jlong handle) {
reinterpret_cast<CppObject *>(handle)->printDetails();
}
A java long is 64 bits, so the above code should work fine on both 32 and 64-bit platforms.
Upvotes: 5
Reputation: 105
#include "stdafx.h"
#include "stdlib.h"
#include <iostream>
#include <iomanip>
#include <stdio.h>
using namespace std;
#include "org_jnp_pkg004_PureCppObjFactory.h"
class NativeObjClass
{
private:
int num_ran;
int obj_num;
public:
static int obj_cnt;
NativeObjClass()
{
obj_cnt++;
obj_num=obj_cnt;
num_ran=rand();
cout<<"Native Object number "<<setfill('0')<<setw(5)<<obj_cnt<<" Random number:"<<num_ran<<endl;
}
int get_obj_num()
{
return obj_num;
}
int get_num_ran()
{
return num_ran;
}
};
int NativeObjClass::obj_cnt=0;
NativeObjClass *nobj_lst;
long nobj_lst_size=0;
JNIEXPORT void JNICALL Java_org_jnp_pkg004_PureCppObjFactory_newCppObj
(JNIEnv *env, jobject obj)
{
jclass thisCls = env->GetObjectClass(obj);
jfieldID fid=env->GetFieldID(thisCls,"cppobjlstsz","J");
NativeObjClass nobj;
jlong java_lst_sz=env->GetLongField(obj,fid);
if(nobj_lst_size==0)
{
nobj_lst_size++;
nobj_lst=(NativeObjClass*)calloc(nobj_lst_size,sizeof(NativeObjClass));
nobj_lst[nobj_lst_size-1]=nobj;
}
else
{
nobj_lst_size++;
nobj_lst=(NativeObjClass*)realloc(nobj_lst,nobj_lst_size*sizeof(NativeObjClass));
nobj_lst[nobj_lst_size-1]=nobj;
}
java_lst_sz++;
env->SetLongField(obj,fid,java_lst_sz);
}
JNIEXPORT void JNICALL Java_org_jnp_pkg004_PureCppObjFactory_printCppObjDetails
(JNIEnv *env, jobject obj, jlong indx)
{
NativeObjClass nobj=nobj_lst[indx];
cout<<"Retrieved Native Object number "<<setfill('0')<<setw(5)<<nobj.get_obj_num()<<" Random number:"<<nobj.get_num_ran()<<endl;
}
Upvotes: 0