6

我目前正在尝试在 Fortran 中编写一个小子程序,以在我的程序出现错误(即加载文件失败或所需文件不存在)时释放内存中所有已分配的变量。此时,必须终止执行,但并非所有可分配对象都必须分配(这取决于错误出现在代码的哪个位置),因此我无法进行清理以释放所有可分配对象。

我目前的方法如下:

SUBROUTINE Cleanup(A)

    REAL(8), ALLOCATABLE, DIMENSION(:) :: A

    IF (ALLOCATED(A)) THEN
        DEALLOCATE(A)
    END IF

END SUBROUTINE

并为每个可分配的对象调用“清理”。问题在于,并非我的所有变量都是维度 1。我在其中一些中最多有三个维度。

我首先考虑为不同的维度编写 3 个不同的子程序并使用重载,但这似乎不是很优雅。

然后我想到,也许我可以传递一个指针而不是实际的参数 A,但我已经用谷歌搜索了,似乎你不能通过指针释放目标变量。

关于如何正确执行此操作的任何想法?

谢谢。

4

1 回答 1

9

My approach to this would use a combination of the following:

  • As of Fortran 95, all local un-saved allocatable variables that are allocated when a procedure finishes are automatically deallocated. Whether this is applicable depends on how your DLL is called, and hence whether you can actually structure things such that all your allocatables are unsaved locals.

  • As of Fortran 2003 (or Fortran 95 + the allocatable TR - this language level is widely supported amongst maintained Fortran compilers) allocatable actual arguments passed to INTENT(OUT) allocatable dummy arguments will be automatically deallocated before the procedure starts execution. Your Cleanup routine in the question just needs to add the declaration of the dummy argument as INTENT(OUT) and then there's no need for the IF test or DEALLOCATE. You still need to write the routine for each type and rank that you need to clean up.

  • Similar to the previous, allocatable components of derived type variables passed to an INTENT(OUT) dummy argument will be automatically deallocated. So you may be able to collect all your allocatable variables together as components in an object of derived type. Cleanup then simply involves passing that object to a procedure with an INTENT(OUT) dummy. INTENT(OUT) here also resets components that have default initialization back to their "default" value. Perhaps there's other cleanup that you need to manually do at this point too (close files, etc).

  • An alternative approach, again using derived types with all your variables as components, is to make the derived type object itself allocatable. When you need to cleanup, simply deallocate that one object - components of it will be automatically deallocated. Fortran 2003 allows for a final procedure to be triggered from this sort of event if you have additional other cleanup to do at this point.

A derived type approach also makes it easy to have multiple instances of whatever your DLL supports independently active at the one time (you just have multiple objects of derived type).

Examples of the derived type approach, given:

TYPE MyType
  REAL, ALLOCATABLE :: variable_one(:)
  INTEGER, ALLOCATABLE :: variable_two(:)
  ...
END TYPE MyType

INTENT(OUT) dummy

TYPE(MyType) :: object
ALLOCATE(object%variable_one(xxx))
ALLOCATE(object%variable_two(yyy))
...
IF (things_have_gone_wrong) CALL Cleanup(object)
...
SUBROUTINE Cleanup(arg)
  TYPE(MyType), INTENT(OUT) :: arg
END SUBROUTINE Cleanup

ALLOCATABLE object.

TYPE(MyType), ALLOCATABLE :: object
ALLOCATE(object)
ALLOCATE(object%variable_one(...))
ALLOCATE(object%variable_two(...))

...
IF (things_have_gone_wrong) DEALLOCATE(object)
于 2013-05-08T10:41:26.560 回答