我有一个复杂的 C++ 对象,我想在我的 Fortran 代码中使用它。一般来说,从 Fortran 调用 C++ 代码是没有问题的(例如只需要提供一个合适的 C 链接接口)。
然而,我的问题是我希望我对 C++ 的 Fortran 调用对我称之为持久对象的对象进行操作:由第一个 init 函数创建并由其他 C++ 函数操作的 C++ 对象。
更具体地说,假设我有以下 C++ 代码
struct A {
public:
void do() { // do something on complicated stuff
private:
... // complicated stuff
};
extern "C" {
void* init_A() {
A* a = new A();
return reinterpret_cast<void*>(a);
}
void doSth(void* ptr_to_A) {
A* a = reinterpret_cast<A*>(ptr_to_A);
a.do();
}
void teardown_A(void* ptr_to_A) {
A* a = reinterpret_cast<A*>(ptr_to_A);
delete a;
}
}
以及以下 fortran 代码(假设它是 main() ):
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_PTR
INTERFACE
TYPE(C_PTR) FUNCTION init_A() BIND(C, NAME='init_A')
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_PTR
IMPLICIT NONE
END FUNCTION init_A
SUBROUTINE doSth(ptr_to_A) BIND(C, NAME='doSth')
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_PTR
IMPLICIT NONE
TYPE(C_PTR), INTENT(IN), VALUE :: ptr_to_A
END SUBROUTINE doSth
SUBROUTINE teardown_A(ptr_to_A) BIND(C, NAME='teardown_A')
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_PTR
IMPLICIT NONE
TYPE(C_PTR), INTENT(IN), VALUE :: ptr_to_A
END SUBROUTINE teardown_A
END INTERFACE
现在在我的真实代码中,它可以编译、链接,有时可以工作,但有时不能:似乎 init_A() 中分配的内存不能被 Fortran 代码保持不变)
我无法在互联网上找到任何相关信息:
- 你知道是否有任何标准机制来确保由 init_A_() 分配的内存保持不变并且仍然由 fortran 代码分配?
- 你知道任何其他适合我的问题的机制吗?
另外,有人可以解释一下为什么没有正确管理内存吗?直到现在,我还以为
Fortran 会向操作系统询问内存,C++ 也是,
操作系统为 Fortan 和 C++ 提供的内存段是不相关的,并且保证不重叠,
如果请求新内存,操作系统不会让 Fortran 使用 C++ 内存,直到 C++ 释放它
C++ 内存通过调用 teardown_A() 或程序(即 Fortran main)终止时释放
编辑:我用 IanH 的答案更新了我的代码,但这仍然不起作用(段错误,在从 Fortran 调用 doSth() 时释放了部分内存
我发布的原始代码如下(供评论参考)
struct A {
public:
void do() { // do something on complicated stuff
private:
... // complicated stuff
};
extern "C" {
void init_A_(long* ptr_to_A) { // ptr_to_A is an output parameter
A* a = new A();
*ptr_to_A = reinterpret_cast<long>(a);
}
void doSth_(long* ptr_to_A) {
A* a = reinterpret_cast<A*>(*ptr_to_A);
a.do();
}
void teardown_A_(long* ptr_to_A) {
A* a = reinterpret_cast<A*>(*ptr_to_A);
delete a;
}
}
和 Fortran 代码:
integer :: ptr_to_A
call init_A(ptr_to_A)
do i=1,10000
call doSth(ptr_to_A)
enddo
call teardown_A(ptr_to_A)