I have recently been reading the book: Scientific software design: the objective oriented way by Rouson et al. and I came across the issue with memory leak in Fortran. It was specifically mentioning the issue with having complex overloading, like: Y=A+b*d , where each element corresponds to a declared type and hence the '=',+,* are all overloaded operators.
Now, I guess if you would use allocatables within a declared type rather than pointers, then you should not worry about memory leak when a function call is returned, Am i right in this assumption?
What about the simple example shown below:
I got two things I would like to understand:
1) Doing 'tes => alloc(100)` is a function call where the pointer tes is pointing to the outcome of the function. I understand function calls in Fortran as they create a copy within themselves workout what needs to be worked out, and then copy it back to the LHS. I am wondering if this could potentially lead to a memory leak since the copied (within the function) has gone out of scope and there is no way we can reach it?
2) When I do `deallocate(tes)`; does it imply that I am deallocating its member 'x' as well, because it is an allocatable and NOT a pointer
Thanks in advance
program mem_leak implicit none type testy real, allocatable :: x(:) end type type(testy), pointer :: tes tes => alloc(100) deallocate(tes) contains function alloc(n) implicit none integer, intent(in) :: n type(testy), pointer :: alloc allocate(alloc) allocate(alloc%X(n)) end function end program
1) There isn't a leak here because the function returns a pointer, and you pointer-assign that to another pointer (tes). It is all too easy to have leaks with pointers if you aren't careful.
2) A deallocate of a pointer to derived type does not deallocate any of the members; that occurs only for allocatable objects.
The language design is such that use of allocatables (instead of pointers) eliminates memory leaks. This assumes a correct implementation. Assigning allocatable variables does entail copying data, whereas pointer assignment does not.
The book mentioned in the original post is really good but in the context of issues mentioned therein re: the Fortran standard and compiler implementations, it reflects more the Fortran 2003 revision and the situation around 10 or more years ago. Nonetheless the attempts with defined operators (*, +) and defined assignment toward "black-board abstraction" such as with D=A+B*C (where A,B,C,D can be objects of rather complicated 'classes' i.e., derived types with various attributes - allocatable/pointer, array dimensions, etc.) remain rather difficult and risky with Fortran as well as C++, though with the latter considerably more enhancements in the language as well as implementations have occurred. Complexities surrounding the "temporary" object toward B*C operation and its handling in a generic, safe, and extensible manner is particularly cumbersome in Fortran; compilers repeatedly fall over and require many, many bug reports which prove exhausting.
As to the code in the original post, should any instruction end up pointing the object 'tes' to a different target, the original allocation becomes unreachable which could result in a memory leak. As pointed out in Quote #2, coders may want to be careful with variables with POINTER attribute in Fortran. If there is need to work with variables with POINTER attribute, an approach to consider as a possible "good coding practice (GCP)" is to have such variables to only point to named targets which themselves have ALLOCATABLE attributes and generally avoid FUNCTION subprograms with a RESULT that has a POINTER attribute to an anonymous target like the one created by the statement in line 21 in the code in the original post but instead work with SUBROUTINE subprograms. Forgetting to NULLIFY the variable with POINTER attribute like the statement marked A below can still present the "dangling pointer" issue depending on what the program does if the coders are not careful, just that the use of ALLOCATABLEs helps reduce the risks with memory leaks.
program test implicit none type testy real, allocatable :: x(:) end type type(testy), allocatable, target :: tes type(testy), pointer :: ptes ptes => null() call alloc(100, tes) ptes => tes print *, "ptes%x(1) = ", ptes%x(1) ptes => null() !<-- A contains subroutine alloc(n, a) integer, intent(in) :: n type(testy), allocatable, intent(out) :: a integer :: i allocate(a) a%x = [( real(i), i=1,n )] end subroutine end program