7

I am currently trying to code a little subroutine in Fortran to deallocate all allocated variables in memory when my program comes to an error, i.e., a failed to load file or an inexistent needed file. At this point, execution must be terminated, but not all allocatables are necessarily allocated (it depends on where on the code the error appeared), so i can't make a cleanup deallocating all of them.

My current approach is the following:

SUBROUTINE Cleanup(A)

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

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

END SUBROUTINE

and call "Cleanup" for every allocatable. The problem with this is that not all my variables are dimension-1. I have up to three dimensions in some of them.

I first thought about writing 3 different subroutines for different dimensions and using overloading, but this do not seems to be very elegant.

Then it came to my mind that maybe i could pass a pointer instead the actuall argument A, but i've googled and it seems you can't deallocate a target variable trough a pointer.

Any ideas about how to do this properly?

Thanks.

3
  • 4
    When execution is terminated, all resources used by your code are automatically freed any way, so you do not have to worry about explicitely deallocating them. Commented May 8, 2013 at 8:54
  • 1
    I know Fortran automatically frees memory, but in this case i'm writing a dll which is called from Labview, so this is who is managing the memory. When the dll comes to an error, Labview suddenly stops, and if i try to re-execute, it will show the message: "Array is already allocated" and shuts down. This means memory is not being deallocated properly.
    – dvilela
    Commented May 8, 2013 at 9:02
  • 1
    Note: real(8) is not guaranteed to be 8 bytes. A portable way is use ISO_FORTRAN_ENV, real (real64) for 64 bits.
    – M. S. B.
    Commented May 8, 2013 at 13:35

1 Answer 1

10

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)
1
  • 3
    Another way i've found to solve this problem is using preprocessor macros: #define Cleanup(A) IF (ALLOCATED(A)) DEALLOCATE(A) When called, Cleanup does the job.
    – dvilela
    Commented May 8, 2013 at 11:56

Not the answer you're looking for? Browse other questions tagged or ask your own question.