【问题标题】:Proper Way to Copy a Complex Derived Type in Fortran在 Fortran 中复制复杂派生类型的正确方法
【发布时间】:2017-08-06 15:17:54
【问题描述】:

我将 Intel Visual Fortran 2015 与 Visual Studio 2012 结合使用。

我尝试了许多不同的方法来尝试在我的代码中创建一个复杂派生类型的副本,但我能想到的每一种方法都会导致内存泄漏,所以我一定是做错了什么。

这是我的问题的简化示例

type Vehicle_T

    real :: time
    real, dimension(3) :: eciPos
    ...
    a bunch of variables
    ...

end Type Vehicle_T

type, extends(Vehicle_Entity_T) :: Aircraft_T
    real :: alt
    ...
    a bunch of variables
    ...
end type Aircraft_T


type Track_T
    real :: tupdated
    ...
    a bunch of variables
    ...

    class(Vehicle_T), pointer :: object

end type Track_T

type(Track_T) :: a, b

a = constructTrack(various values)

b = copyTrack(a)

contains

!The simplest way I've found that works but causes memory leak
function copyTrack(inTrack) result(outTrack)

    type(Track_T), intent(in) :: inTrack
    type(Track_T) :: outTrack

    outTrack = inTrack
    allocate(outTrack%object, source = inTrack%object)

end function copyTrack

!Another method that causes a memory leak
function copyTrack2(inTrack) result(outTrack)

    type(Track_T), intent(in) :: inTrack
    type(Track_T) :: outTrack

    outTrack%tupdated = inTrack%tupdated
    ...copy all of the rest of the values...

    if(associated(outTrack%object)) deallocate(outTrack%object)
    allocate(outTrack%object, source = inTrack%object)

end function copyTrack2

【问题讨论】:

  • 我没有,(第二个答案:stackoverflow.com/questions/20291814/…)但是,我也尝试过 nullify ,但仍然存在内存泄漏。
  • 实际上,我发现这种方法存在问题。我说这行得通是错误的。我会修复原来的帖子。我当时做错的是我正在释放输入对象,然后尝试将该对象复制到输出对象中。
  • deallocate(outTrack%object) 解除了 outTrack%object 的关联,但也解除了其原始目标 inTrack%object 的分配。
  • 感谢您指出这一点。我现在明白了,但这不是主要问题。
  • 为什么对象组件是指针?如果在复制具有该组件的派生类型的对象时正在复制与该指针组件关联的事物,则表明派生类型拥有与该指针关联的对象,并且指针组件的使用与此不一致. (存在例外。)

标签: pointers memory-leaks fortran


【解决方案1】:

当你这样做时,你必须照顾 object 组件 b

`b` = some_new_object

无论新对象来自何处。 无论你在你的函数中做什么,它总是会泄漏。(或者不,如果你使用终结,见下文。我还没有使用它,因为许多编译器不完全支持它,主要是 gfortran .)

泄漏的原因是b 包含一个指针组件,该组件只能从b 访问。在内部赋值期间指针将被覆盖,指针的目标将丢失。

使用子程序:

implicit none

type Vehicle_T

    real :: time = 0
    real, dimension(3) :: eciPos = 0


end Type Vehicle_T

type, extends(Vehicle_T) :: Aircraft_T
    real :: alt

end type Aircraft_T


type Track_T
    real :: tupdated

    class(Vehicle_T), pointer :: object => null()

end type Track_T

type(Track_T) :: a, b

integer :: i

allocate(Aircraft_T :: a%object)

do i = 1, 10
  call copyTrack(b, a)
end do

deallocate(a%object)
deallocate(b%object)

contains


subroutine copyTrack(outTrack, inTrack)

    type(Track_T), intent(in) :: inTrack
    type(Track_T) :: outTrack

    if (associated(outTrack%object)) deallocate(outTrack%object)
    outTrack = inTrack
    allocate(outTrack%object, source = inTrack%object)

end subroutine copyTrack



end

或者更好的重载赋值:

module types
  implicit none

  type Vehicle_T

      real :: time = 0
      real, dimension(3) :: eciPos = 0


  end Type Vehicle_T

  type, extends(Vehicle_T) :: Aircraft_T
      real :: alt

  end type Aircraft_T


  type Track_T
      real :: tupdated

      class(Vehicle_T), pointer :: object => null()
  contains
      procedure :: copyTrack
      generic :: assignment(=) => copyTrack
  end type Track_T

contains

    subroutine copyTrack(outTrack, inTrack)

        type(Track_T), intent(in) :: inTrack
        class(Track_T), intent(inout) :: outTrack

        if (associated(outTrack%object)) deallocate(outTrack%object)

        allocate(outTrack%object, source = inTrack%object)

    end subroutine copyTrack



end module


  use types

  implicit none

  type(Track_T) :: a, b

  integer :: i

  allocate(Aircraft_T :: a%object)

  do i = 1, 10
    b = a
  end do

  deallocate(a%object)
  deallocate(b%object)

end

具有函数和终结性。 希望不会在 ifort 中泄漏,但会在 gfortran 中泄漏。

module types
  implicit none

  type Vehicle_T

      real :: time = 0
      real, dimension(3) :: eciPos = 0


  end Type Vehicle_T

  type, extends(Vehicle_T) :: Aircraft_T
      real :: alt

  end type Aircraft_T


  type Track_T
      real :: tupdated

      class(Vehicle_T), pointer :: object => null()
  contains
    final :: finalize_Track
  end type Track_T

contains

    function copyTrack(inTrack) result(outTrack)

        type(Track_T), intent(in) :: inTrack
        type(Track_T) :: outTrack

        outTrack = inTrack
        allocate(outTrack%object, source = inTrack%object)

    end function copyTrack

   subroutine finalize_Track(t)
     type(Track_T), intent(inout) :: t
     if (associated(t%object)) deallocate(t%object)
   end subroutine
end module


  use types

  type(Track_T) :: a, b

  integer :: i

  allocate(Aircraft_T :: a%object)

  do i = 1, 10
    b = copyTrack(a)
  end do

  deallocate(a%object)
  deallocate(b%object)

end

【讨论】:

  • 谢谢。几分钟前,我发现这是意图(out)的问题,并且正在努力实施修复。赋值超载很时髦。我很感激。
  • 您能否(稍微)解释一下为什么该作业总是(没有最终确定)泄漏?
  • 我以前没有听说过finalization,我得看看,因为我没有关注它的作用。最后的释放是必要的吗?我的印象是,在程序(或函数)结束时,不再在范围内的变量会自动释放。
  • @francescalus 我理解它的方式(我可能错了)是,如果你使用“intent(out)”(或一个函数,因为结果是隐含的“intent(out)” ) 它导致变量自动解除关联而不被释放,这反过来导致“关联(对象)”返回 .false。
  • 不,deallocates 不是必需的,但对于从内存泄漏调试工具(如 valgrind)获得干净的输出是必需的,因为主程序变量隐含为 save 并且未最终确定或解除分配。
猜你喜欢
  • 2020-02-09
  • 1970-01-01
  • 2012-10-23
  • 2019-03-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-16
  • 2014-04-16
相关资源
最近更新 更多