Fortran массив производных типов и утечек памяти несмотря на завершение
Я определил производный тип и столкнулся с некоторыми проблемами с освобождением памяти, хотя я написал окончательную процедуру. Код выглядит следующим образом
module ModuleCoordinate
implicit none
type :: TCoordinate
real(8),dimension(:),pointer :: Coordinate => NULL()
contains
procedure :: TCoordinateAssignment
generic,public :: Assignment(=) => TCoordinateAssignment
final :: TCoordinateDel
end type TCoordinate
interface TCoordinate
module procedure :: TCoordinateInit
end interface TCoordinate
contains
subroutine TCoordinateDel(self)
type(TCoordinate),intent(inout) :: self
if(associated(self%Coordinate))deallocate(self%Coordinate)
end subroutine TCoordinateDel
subroutine TCoordinateAssignment(O1,O2)
class(TCoordinate),intent(out) :: O1
type(TCoordinate),intent(in) :: O2
if(associated(O2%Coordinate))allocate(O1%Coordinate,source=O2%Coordinate)
end subroutine TCoordinateAssignment
type(TCoordinate) function TCoordinateInit(IVal1,IVal2) result(self)
real(8),intent(in) :: IVal1,IVal2
allocate(self%Coordinate(2))
self%Coordinate=(/IVal1,IVal2/)
end function TCoordinateInit
end module ModuleCoordinate
Тестовый код выглядит следующим образом
program test
implicit none
integer(4),parameter :: NLoop=40000
integer(4) :: i
do i=1,NLoop
call TestMemory1()
call TestMemory2()
end do
pause
end program test
subroutine TestMemory1()
use ModuleCoordinate
implicit none
integer(4),parameter :: DN=10
integer(4) :: i
type(TCoordinate),dimension(DN) :: a
do i=1,DN
a(i)=TCoordinate(1.0_8,1.0_8)
end do
end subroutine TestMemory1
subroutine TestMemory2()
use ModuleCoordinate
implicit none
type(TCoordinate) :: b1,b2,b3,b4,b5,b6,b7,b8,b9,b10
b1=TCoordinate(1.0_8,1.0_8)
b2=TCoordinate(1.0_8,1.0_8)
b3=TCoordinate(1.0_8,1.0_8)
b4=TCoordinate(1.0_8,1.0_8)
b5=TCoordinate(1.0_8,1.0_8)
b6=TCoordinate(1.0_8,1.0_8)
b7=TCoordinate(1.0_8,1.0_8)
b8=TCoordinate(1.0_8,1.0_8)
b9=TCoordinate(1.0_8,1.0_8)
b10=TCoordinate(1.0_8,1.0_8)
end subroutine TestMemory2
Оказывается, подпрограмма TestMemory2
пока нормально TestMemory1
это не так, что означает, что при объявлении массива этого производного типа последняя процедура не работает и происходит утечка памяти.
Однако, если я удалю => NULL()
справа от Coordinate
в определении этого производного типа обе подпрограммы, кажется, работают хорошо.
Что имеет значение, когда указатель Coordinate
освобождается? Компилятором является ifort_2013_sp1.3.174, если это имеет значение.
1 ответ
В описании процесса завершения мы видим (Fortran 2008, 4.5.6.2)
Если динамический тип сущности имеет заключительную подпрограмму, фиктивный аргумент которой имеет те же параметры типа вида и ранга, что и завершаемая сущность, он вызывается с сущностью в качестве фактического аргумента. В противном случае, если есть элементарная конечная подпрограмма, фиктивный аргумент которой имеет те же параметры типа вида, что и завершаемая сущность, она вызывается с сущностью в качестве фактического аргумента. В противном случае подпрограмма не вызывается в этой точке.
Существует заключительная подпрограмма для производного типа, предоставленная только для скалярных (ранг-0) объектов. Чтобы получить финализацию для вашей сущности ранга 1, самый простой способ (кажется, в данном случае) - сделать подпрограмму элементарной.
Я немного не хочу упоминать =>NULL()
аспект, поскольку у меня нет текущих средств проверки того, что я собираюсь написать, но я буду размышлять.
Без =>NULL()
инициализация по умолчанию компонент указателя имеет неопределенный статус ассоциации. Это означает, что когда вы делаете
b1=TCoordinate(1.0_8,1.0_8)
происходят интересные вещи.
В рамках задания b1
завершается при входе в TCoordinateAssignment
, Финализация включает в себя вызов associated
с указателем, который имеет неопределенный статус ассоциации. Это недопустимо (в результате чего может возникнуть любой результат).