I have a C++ library that is called by Java through a SWIG-based interface. On the Java side, I build up a structure containing pointers to arrays of other structures, using the default struct interface and carrays.i
's %array_class
.
Because Java's garbage collector is not aware of the members of the top-level struct, the array is sometimes freed, whereon its finalizer delete[]
s its backing memory. I need a way around this, preferably without duplicating the struct in Java, since it's rather large.
A minimal example looks like this (although it probably won't trigger the bug since it doesn't do much):
C++/SWIG:
%module example
%include "carrays.i"
%array_class(object, objectArray);
struct object {
unsigned int id;
char *name;
};
struct data {
size_t nobjects;
object *objects;
};
void use_data(data*);
Java:
public class Example {
private static data writeData() {
data d = new data();
objectArray os = new objectArray(3);
for (int i = 0; i < 3; i++) {
object o = new object();
o.setId(i);
o.setName("obj" + i);
os.setitem(i, o);
}
d.setNobjects(3);
d.setObjects(os.cast());
return d;
}
public static void main(String[] args) {
data d = writeData();
example.use_data(d);
}
}
There's a couple of possible solutions to this. The simplest is to wrap a function that can create
object
s without Java "owning" the memory. This might look something like:You can actually modify the
swigCMemOwn
boolean
after creation. A typemap should be able to inject this at the appropriate place (when theobject
is handed tosetitem
). For example you could write:This needs to be before the
object
class is first seen and allows you to write something like:instead of
os.setitem(i, o);
.A variation on this theme would be to use a
javain
typemap to replace the defaultsetitem
implementation in the Java proxy such that it calls a function (you supply) on theobject
to change the ownership, e.g.:before the
%include "carrays.i"
and a correspondingdisown()
via%typemap(javacode) object
. (swigCMemOwn
isprotected
, so theobjectArray
can't modify that directly).There are other approaches possible too, which involve setting the ownership also. The ones I've shown are the easiest I think though.
Alternatively, another common work around would be to keep a reference to the Java proxy Object hanging around, by assigning it to a member variable. In this instance since you potentially have lots of objects that would have to be a container itself though.