gpt4 book ai didi

java - SWIG (v1.3.29) 生成的 C++ 到 Java Vector 类无法正常运行

转载 作者:搜寻专家 更新时间:2023-10-30 21:21:51 27 4
gpt4 key购买 nike

我有一些 native C++ 代码,我正在使用 SWIG 将它们转换为 Java,以便我的 Java 应用程序可以使用它。特别是有一些函数返回 std::vector。这是我的界面文件的片段:

%include "std_vector.i"
namespace std {
%template(Vector) vector<double>;
%template(Matrix) vector<vector<double> >;
}

%include "std_string.i"
std_string.istd_vector.i包含在我正在使用的 SWIG 构建中。我的第一个惊喜是 Java 输出包括 SWIG 的“自己”版本的 Vector 类(而不是使用 java.util.Vector)。我真正的问题是从这些函数返回的 vector 似乎不起作用。例如,我无法使用 get() 检索它们的内容。 (有时会导致程序崩溃)或 size()函数返回负值。我知道 Vector s 包含数据,因为我编码了相同函数的“字符串”版本,这些函数只是遍历 Vector s(回到 native C++ 代码中)并返回以逗号分隔的内容 String值(value)。虽然这是一个有效的解决方法,但最终我希望它能够正常工作,我能够接收和操作 Vectors .任何帮助/提示将不胜感激。

最佳答案

用于包装的适当基础类型 std::vector在 Java 中是 java.util.AbstractList .使用 java.util.Vector作为基础会很奇怪,因为您最终会得到两组存储,其中一组在 std::vector 中。 ,以及 java.util.Vector 中的一个.

SWIG 不为您执行此操作的原因是因为 you can't have AbstractList<double> in Java ,它必须是 AbstractList<Double> ( Double 继承自 Objectdouble 是原始类型)。

说了这么多,我整理了一个小例子来包装 std::vector<double>std::vector<std::vector<double> >在 Java 中很好。它并不完整,但它支持 Java 和 set() 中的“for each”迭代风格。/get()在元素上。展示如何在需要时实现其他东西就足够了。

我将在我们进行时分部分讨论接口(interface)文件,但基本上它都是顺序和完整的。

num.i 开头它定义了我们的模块 num :

%module num

%{
#include <vector>
#include <stdexcept>

std::vector<double> testVec() {
return std::vector<double>(10,1.0);
}

std::vector<std::vector<double> > testMat() {
return std::vector<std::vector<double> >(10, testVec());
}
%}

%pragma(java) jniclasscode=%{
static {
try {
System.loadLibrary("num");
} catch (UnsatisfiedLinkError e) {
System.err.println("Native code library failed to load. \n" + e);
System.exit(1);
}
}
%}

我们有 #include s 用于生成的 num_wrap.cxx和两个用于测试的函数实现(它们可以在一个单独的文件中,我只是出于懒惰/方便将它们放在这里)。
%pragma(java) jniclasscode= 还有一个技巧。我喜欢在 Java SWIG 接口(interface)中使用它来使共享对象/DLL 为接口(interface)的用户透明地加载。

接口(interface)文件中接下来是 std::vector 的部分我们要包装。我没有使用 std_vector.i因为我们需要做一些改变:
namespace std {

template<class T> class vector {
public:
typedef size_t size_type;
typedef T value_type;
typedef const value_type& const_reference;
%rename(size_impl) size;
vector();
vector(size_type n);
size_type size() const;
size_type capacity() const;
void reserve(size_type n);
%rename(isEmpty) empty;
bool empty() const;
void clear();
void push_back(const value_type& x);
%extend {
const_reference get_impl(int i) throw (std::out_of_range) {
// at will throw if needed, swig will handle
return self->at(i);
}
void set_impl(int i, const value_type& val) throw (std::out_of_range) {
// at can throw
self->at(i) = val;
}
}
};
}

这里的主要变化是 %rename(size_impl) size; ,它告诉 SWIG 暴露 size()来自 std::vectorsize_impl反而。我们需要这样做,因为 Java 期望 size返回 int其中 std::vector版本返回 size_type这很可能不会是 int .

接下来在接口(interface)文件中,我们告诉它我们想要实现哪些基类和接口(interface),并编写一些额外的 Java 代码来强制具有不兼容类型的函数之间的内容:
%typemap(javabase) std::vector<double> "java.util.AbstractList<Double>"
%typemap(javainterface) std::vector<double> "java.util.RandomAccess"
%typemap(javacode) std::vector<double> %{
public Double get(int idx) {
return get_impl(idx);
}
public int size() {
return (int)size_impl();
}
public Double set(int idx, Double d) {
Double old = get_impl(idx);
set_impl(idx, d.doubleValue());
return old;
}

%}

%typemap(javabase) std::vector<std::vector<double> > "java.util.AbstractList<Vector>"
%typemap(javainterface) std::vector<std::vector<double> > "java.util.RandomAccess"
%typemap(javacode) std::vector<std::vector<double> > %{
public Vector get(int idx) {
return get_impl(idx);
}
public int size() {
return (int)size_impl();
}
public Vector set(int idx, Vector v) {
Vector old = get_impl(idx);
set_impl(idx, v);
return old;
}

%}

这设置了 java.util.AbstractList<Double> 的基类为 std::vector<double>java.util.AbstractList<Vector>std::vector<std::vector<double> > ( Vector 是我们将在接口(interface)的 Java 端调用的 std::vector<double>)。

我们还提供了 get 的实现和 set在可以处理 double 的 Java 端至 Double转换并再次返回。

最后在界面中我们添加:
namespace std {
%template(Vector) std::vector<double>;
%template(Matrix) std::vector<vector<double> >;
}

std::vector<double> testVec();
std::vector<std::vector<double> > testMat();

这告诉 SWIG 引用 std::vector<double> (具体类型)为 Vectorstd::vector<vector<double> > 类似如 Matrix .我们还告诉 SWIG 公开我们的两个测试函数。

接下来, test.java ,一个简单的 main在 Java 中稍微练习一下我们的代码:
import java.util.AbstractList;

public class test {
public static void main(String[] argv) {
Vector v = num.testVec();
AbstractList<Double> l = v;
for (Double d: l) {
System.out.println(d);
}
Matrix m = num.testMat();
m.get(5).set(5, new Double(5.0));
for (Vector col: m) {
for (Double d: col) {
System.out.print(d + " ");
}
System.out.println();
}
}
}

为了构建和运行它,我们这样做:
swig -java -c++ num.i
g++ -Wall -Wextra num_wrap.cxx -shared -I/usr/lib/jvm/java-6-sun/include -I/usr/lib/jvm/java-6-sun/include/linux/ -o libnum.so

javac test.java && LD_LIBRARY_PATH=. java test

我在 Linux/x86 上使用 g++ 4.4 版和 SWIG 1.3.40 对此进行了测试。

完整版 num.i可以找到 here ,但始终可以通过将每个部分粘贴到一个文件中来从这个答案中重建。

我还没有从 AbstractList 实现的事情:
  • add() - 可以通过 push_back() 实现, std_vector.i 甚至尝试实现默认兼容的东西,但它不适用于 Double对比 double问题或匹配 AbstractList 中指定的返回类型(不要忘记增加 modCount )
  • remove() - 不太适合 std::vector在时间复杂度方面,但也不是不可能实现(同样使用 modCount )
  • 一个接受另一个 Collection 的构造函数建议使用,但未在此处实现。可以在同一个地方实现set()get()是,但需要 $javaclassname正确命名生成的构造函数。
  • 你可能想使用类似 this 的东西检查 size_type -> int转换在 size()是理智的。
  • 关于java - SWIG (v1.3.29) 生成的 C++ 到 Java Vector 类无法正常运行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8145605/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com