Conversation
fpenunuri
left a comment
There was a problem hiding this comment.
While using a finalizer (final :: dual_finalizer_${name}$${bits}$) for the
dual type upon leaving scope is a nice approach, it may cause conflicts
with some functions and subroutines that use the elemental attribute.
Perhaps the following approach would be more convenient:
...
public :: clear_dual
...
!---
interface clear_dual
#:for name, type, label in FLAVOURS
#:for bits in REALMODEL
module procedure clear_dual_${label}$${bits}$
#:endfor
#:endfor
end interface clear_dual
!--
...
contains
!---
#:for name, type, label in FLAVOURS
#:for bits in REALMODEL
subroutine clear_dual_${label}$${bits}$(x)
type(dual_${name}$${bits}$), intent(inout) :: x
if (allocated(x%f)) deallocate(x%f)
end subroutine clear_dual_${label}$${bits}$
#:endfor
#:endfor
!---
|
Please note, that the finalizer as defined in the PR has no actual effect IMO. The |
|
@aradi That suggests explicit finalization is not yet needed for this structure. |
|
@bhourahine Indeed, the derived type in its current form does not require any finalization. Also, as you mention |
|
I agree — the finalizer should be avoided if possible. However, in a For instance program test1 integer, parameter :: prec = real64 z0 = (1.1_prec, 2.2_prec) ! call clear_dual(z) ! <--- Without this, Valgrind reports: possibly lost: end program test1 |
|
@fpenunuri Please note, that this message of valgrind is a false positive, allocatables are always warranted to be automatically deallocated when going out of scope, so no memory is lost. The reason you get the valgrind message here, because variables declared in the scope of a program test1
use iso_fortran_env, only : real64
use dnaoad
implicit none
integer, parameter :: prec = real64
integer, parameter :: order = 5
block
complex(prec) :: z0
type(dual_cmplx64) :: z
z0 = (1.1_prec, 2.2_prec)
call initialize_dual(z, order)
z = z0
call z%set_derivative(1, cmplx(1, 0, prec))
call clear_dual(z)
end block
end program test1or alternatively program test1
use iso_fortran_env, only : real64
use dnaoad
implicit none
integer, parameter :: prec = real64
integer, parameter :: order = 5
call main()
contains
subroutine main()
complex(prec) :: z0
type(dual_cmplx64) :: z
z0 = (1.1_prec, 2.2_prec)
call initialize_dual(z, order)
z = z0
call z%set_derivative(1, cmplx(1, 0, prec))
call clear_dual(z)
end subroutine main
end program test1Both versions deallocate the allocatable components explicitely (when the instances leave the |
|
@aradi That makes sense, thanks. In your experience, what do you think is the Would you prefer: |
|
@fpenunuri I'd go with the first or the second option. The block and subroutine approaches are completely equivalent, so it really depends on your taste which one you prefer. Defining and calling cleanup routines should be avoided IMO as it just adds additional clutter for something which the language is able to do for you automatically anyway. And letting valgrind giving you false positives should be also avoided. as at some point you might ignore a real valgrind error/warning, just because you think, it is the usual false positive... |
Deallocates internal structure storage whenever dual objects go out of scope or are deallocated, including trapping for cases like intent(out) start up where the internals are not allocated on initial finalization.