SWIG 和 shared_ptr:javaout 类型映射未应用于地图模板
SWIG and shared_ptr: javaout typemap not applied to map template
问题
我正在开发一个 Android 应用程序,其中我必须在 Java 代码和 C++ 代码之间传递一个 OpenCV Mat。为此,我创建了以下工作正常的 SWIG 类型映射:
%include "std_map.i"
%include "std_shared_ptr.i"
...
%shared_ptr(cv::Mat)
...
// normal typemaps for cv::Mat w/o shared_ptr
%typemap(jstype) cv::Mat, cv::Mat& "org.opencv.core.Mat"
%typemap(javain) cv::Mat, cv::Mat& "$javainput.getNativeObjAddr()"
%typemap(jtype) cv::Mat, cv::Mat& "long"
%typemap(jni) cv::Mat, cv::Mat& "jlong"
%typemap(in) cv::Mat, cv::Mat& {
= *(cv::Mat **)&$input;
}
%typemap(javaout) cv::Mat, cv::Mat& {
return new org.opencv.core.Mat($jnicall);
}
// rather hacky javaout typemap override for the shared_ptr
%typemap(javaout) std::shared_ptr< cv::Mat > {
long cPtr = $jnicall;
return (cPtr == 0) ? null : new org.opencv.core.Mat(cPtr);
}
无论如何,在某些时候我必须return一个std::map<std::string, std::shared_ptr<cv::Mat>>
到Java。我使用带有
的地图模板完成了此操作
%template(Map_String_Shared_ptr_Mat) std::map<std::string, std::shared_ptr<cv::Mat>>;
在 Java 中生成以下 get
方法:
public org.opencv.core.Mat get(String key) {
long cPtr = xyJNI.Map_String_Shared_ptr_Mat_get(swigCPtr, this, key);
return (cPtr == 0) ? null : new org.opencv.core.Mat(cPtr, true);
}
它没有使用之前提供的 javaout 类型映射。 (它在函数 returning a std::shared_ptr<cv::Mat>
但不在地图模板中起作用)
到目前为止我尝试了什么
我试图通过
插入我自己的get
方法
%typemap(javacode) std::map<std::string, std::shared_ptr<cv::Mat>> %{
public org.opencv.Mat get{
...
}
%};
但这会导致冲突,因为存在两个 get 方法。
此外,当我首先尝试 %ignore
get
方法时,没有创建相应的 xyJNI.Map_String_Shared_ptr_Mat_get(swigCPtr, this, key);
,因此我无法提供我自己的 get
问题
现在我需要一种方法来告诉 SWIG 应用该 javaout 类型映射。但是我也可以通过覆盖 get
方法主体的方法来为 Mat 使用正确的构造函数。
希望有人能帮我解决这个问题
注意:我不关心 Map_String_Shared_ptr_Mat
不是 Java 中的真实 Map
。这对我来说不是问题
编辑:
添加了 shared_ptr javaout typemap
不幸的是,我无法找到将 javaout
类型映射应用于 Mat_String_Shared_ptr_Mat.get()
或替换 Mat_String_Shared_ptr_Mat.get()
.[=30= 的方法内容的解决方案]
我最终得到的解决方法是 returns 在 getPlain()
方法中引用 cv::Mat
(所以不是 shared_ptr
),类型映射是应用。
这当然不是我正在寻找的完美解决方案,但它可能会帮助其他面临类似问题的人。
解决方案
%include "std_map.i"
// 1.
%typemap(javaout) cv::Mat, cv::Mat& {
return new org.opencv.core.Mat($jnicall);
}
...
// 2.
%ignore std::map<std::string, std::shared_ptr<cv::Mat>>::get;
// 3.
%template(Map_String_Shared_ptr_Mat) std::map<std::string, std::shared_ptr<cv::Mat>>;
// 4.
%extend std::map<std::string, std::shared_ptr<cv::Mat>>{
const cv::Mat& getPlain(const std::string& key) throw (std::out_of_range) {
std::map<std::string,std::shared_ptr< cv::Mat > >::iterator i = self->find(key);
if (i != self->end())
return *i->second;
else
throw std::out_of_range("key not found");
}
}
- cv::Mat 的类型映射(与 shared_ptr 类型映射不同)应用于包装映射
- 忽略
get
函数(第4步会自行实现)
- 让 SWIG 通过
std_map.i
中定义的模板创建包装器
- 通过向地图添加
getPlain
函数来扩展包装器。此函数 returns 引用 cv::Mat
对象本身,而不是 shared_ptr
。创建 Java 代码时应用步骤 1 的 javaout
类型映射
输出
在 运行 SWIG 之后,Java class Map_String_Shared_ptr_Mat
包含所需的 getPlain
方法:
public org.opencv.core.Mat getPlain(String key) {
return new org.opencv.core.Mat(xyJNI.Map_String_Shared_ptr_Mat_getPlain(swigCPtr, this, key));
}
更新
注意:此部分特定于cv::Mat
由于 Java 中 cv::Mat 的实现,我不得不更改实现以在 C++ 中执行按引用调用。
这是因为 Java Mat 实现存储了指向 C++ Mat 的指针。在 finalize
方法中,C++ 对象被释放。在之前的实现中,对象可能已经被删除,这将导致 SIGSEGV 崩溃。
因此将实施更改为以下内容:
%extend std::map<std::string, std::shared_ptr<cv::Mat>>{
void getPlain(const std::string& key, cv::Mat& dest) throw (std::out_of_range) {
std::map<std::string,std::shared_ptr< cv::Mat > >::iterator i = self->find(key);
if (i != self->end()){
(*i->second).copyTo(dest);
} else{
throw std::out_of_range("key not found");
}
}
将数据复制到第二个参数中的 Mat,它本身是在 Java 中创建的(因此不会产生已释放的段错误)。
解决方案可以调整为 create/wrap 分别实现 set
和其他功能。
注意:我也最终使用了post中介绍的一些方法:Passing Java Map<String, String> to C++ method using SWIG,绝对值得一看。
问题
我正在开发一个 Android 应用程序,其中我必须在 Java 代码和 C++ 代码之间传递一个 OpenCV Mat。为此,我创建了以下工作正常的 SWIG 类型映射:
%include "std_map.i"
%include "std_shared_ptr.i"
...
%shared_ptr(cv::Mat)
...
// normal typemaps for cv::Mat w/o shared_ptr
%typemap(jstype) cv::Mat, cv::Mat& "org.opencv.core.Mat"
%typemap(javain) cv::Mat, cv::Mat& "$javainput.getNativeObjAddr()"
%typemap(jtype) cv::Mat, cv::Mat& "long"
%typemap(jni) cv::Mat, cv::Mat& "jlong"
%typemap(in) cv::Mat, cv::Mat& {
= *(cv::Mat **)&$input;
}
%typemap(javaout) cv::Mat, cv::Mat& {
return new org.opencv.core.Mat($jnicall);
}
// rather hacky javaout typemap override for the shared_ptr
%typemap(javaout) std::shared_ptr< cv::Mat > {
long cPtr = $jnicall;
return (cPtr == 0) ? null : new org.opencv.core.Mat(cPtr);
}
无论如何,在某些时候我必须return一个std::map<std::string, std::shared_ptr<cv::Mat>>
到Java。我使用带有
%template(Map_String_Shared_ptr_Mat) std::map<std::string, std::shared_ptr<cv::Mat>>;
在 Java 中生成以下 get
方法:
public org.opencv.core.Mat get(String key) {
long cPtr = xyJNI.Map_String_Shared_ptr_Mat_get(swigCPtr, this, key);
return (cPtr == 0) ? null : new org.opencv.core.Mat(cPtr, true);
}
它没有使用之前提供的 javaout 类型映射。 (它在函数 returning a std::shared_ptr<cv::Mat>
但不在地图模板中起作用)
到目前为止我尝试了什么
我试图通过
插入我自己的get
方法
%typemap(javacode) std::map<std::string, std::shared_ptr<cv::Mat>> %{
public org.opencv.Mat get{
...
}
%};
但这会导致冲突,因为存在两个 get 方法。
此外,当我首先尝试 %ignore
get
方法时,没有创建相应的 xyJNI.Map_String_Shared_ptr_Mat_get(swigCPtr, this, key);
,因此我无法提供我自己的 get
问题
现在我需要一种方法来告诉 SWIG 应用该 javaout 类型映射。但是我也可以通过覆盖 get
方法主体的方法来为 Mat 使用正确的构造函数。
希望有人能帮我解决这个问题
注意:我不关心 Map_String_Shared_ptr_Mat
不是 Java 中的真实 Map
。这对我来说不是问题
编辑: 添加了 shared_ptr javaout typemap
不幸的是,我无法找到将 javaout
类型映射应用于 Mat_String_Shared_ptr_Mat.get()
或替换 Mat_String_Shared_ptr_Mat.get()
.[=30= 的方法内容的解决方案]
我最终得到的解决方法是 returns 在 getPlain()
方法中引用 cv::Mat
(所以不是 shared_ptr
),类型映射是应用。
这当然不是我正在寻找的完美解决方案,但它可能会帮助其他面临类似问题的人。
解决方案
%include "std_map.i"
// 1.
%typemap(javaout) cv::Mat, cv::Mat& {
return new org.opencv.core.Mat($jnicall);
}
...
// 2.
%ignore std::map<std::string, std::shared_ptr<cv::Mat>>::get;
// 3.
%template(Map_String_Shared_ptr_Mat) std::map<std::string, std::shared_ptr<cv::Mat>>;
// 4.
%extend std::map<std::string, std::shared_ptr<cv::Mat>>{
const cv::Mat& getPlain(const std::string& key) throw (std::out_of_range) {
std::map<std::string,std::shared_ptr< cv::Mat > >::iterator i = self->find(key);
if (i != self->end())
return *i->second;
else
throw std::out_of_range("key not found");
}
}
- cv::Mat 的类型映射(与 shared_ptr 类型映射不同)应用于包装映射
- 忽略
get
函数(第4步会自行实现) - 让 SWIG 通过
std_map.i
中定义的模板创建包装器
- 通过向地图添加
getPlain
函数来扩展包装器。此函数 returns 引用cv::Mat
对象本身,而不是shared_ptr
。创建 Java 代码时应用步骤 1 的javaout
类型映射
输出
在 运行 SWIG 之后,Java class Map_String_Shared_ptr_Mat
包含所需的 getPlain
方法:
public org.opencv.core.Mat getPlain(String key) {
return new org.opencv.core.Mat(xyJNI.Map_String_Shared_ptr_Mat_getPlain(swigCPtr, this, key));
}
更新
注意:此部分特定于cv::Mat
由于 Java 中 cv::Mat 的实现,我不得不更改实现以在 C++ 中执行按引用调用。
这是因为 Java Mat 实现存储了指向 C++ Mat 的指针。在 finalize
方法中,C++ 对象被释放。在之前的实现中,对象可能已经被删除,这将导致 SIGSEGV 崩溃。
因此将实施更改为以下内容:
%extend std::map<std::string, std::shared_ptr<cv::Mat>>{
void getPlain(const std::string& key, cv::Mat& dest) throw (std::out_of_range) {
std::map<std::string,std::shared_ptr< cv::Mat > >::iterator i = self->find(key);
if (i != self->end()){
(*i->second).copyTo(dest);
} else{
throw std::out_of_range("key not found");
}
}
将数据复制到第二个参数中的 Mat,它本身是在 Java 中创建的(因此不会产生已释放的段错误)。
解决方案可以调整为 create/wrap 分别实现 set
和其他功能。
注意:我也最终使用了post中介绍的一些方法:Passing Java Map<String, String> to C++ method using SWIG,绝对值得一看。