Fortran 90函数返回指针

时间:2014-06-03 17:08:38

标签: pointers memory memory-management fortran fortran90

我看到了这个问题:

Fortran dynamic objects

如果我安全地编写了以下函数(不允许内存泄漏),那么接受的答案让我有疑问

   function getValues3D(this) result(vals3D)
     implicit none
     type(allBCs),intent(in) :: this
     real(dpn),dimension(:,:,:),pointer :: vals3D
     integer,dimension(3) :: s
     if (this%TF3D) then
       s = shape(this%vals3D)
       if (associated(this%vals3D)) then
            stop "possible memory leak - p was associated"
       endif
       allocate(vals3D(s(1),s(2),s(3)))
       vals3D = this%vals3D
     else; call propertyNotAssigned('vals3D','getValues3D')
     endif
   end function

当我运行我的代码时会出现此警告,但如果之前(对此功能)设置了,this%vals3D不应该关联吗?我目前遇到了内存错误,当我在其中引入一个带有此功能的新模块时,它们就开始出现了。

非常感谢任何帮助。

我认为我不够具体。我想创建以下类,并且知道如何在内存方面安全地实现类。那就是:

   module vectorField_mod
   use constants_mod
   implicit none

   type vecField1D
     private
     real(dpn),dimension(:),pointer :: x
     logical :: TFx = .false.
   end type

   contains

   subroutine setX(this,x)
     implicit none
     type(vecField1D),intent(inout) :: this
     real(dpn),dimension(:),target :: x
     allocate(this%x(size(x)))
     this%x = x
     this%TFx = .true.
   end subroutine

   function getX(this) result(res)
     implicit none
     real(dpn),dimension(:),pointer :: res
     type(vecField1D),intent(in) :: this
     nullify(res)
     allocate(res(size(this%x)))
     if (this%TFx) then
       res = this%x
     endif
   end function

   end module

以下代码测试此模块

   program testVectorField
   use constants_mod
   use vectorField_mod
   implicit none

   integer,parameter :: Nx = 150
   real(dpn),parameter :: x_0 = 0.0
   real(dpn),parameter :: x_N = 1.0
   real(dpn),parameter :: dx = (x_N - x_0)/dble(Nx-1)
   real(dpn),dimension(Nx) :: x = (/(x_0+dble(i)*dx,i=0,Nx-1)/)
   real(dpn),dimension(Nx) :: f
   real(dpn),dimension(:),pointer :: fp
   type(vecField1D) :: f1
   integer :: i

   do i=1,Nx
    f(i) = sin(x(i))
   enddo

   do i=1,10**5
     call setX(f1,f) ! 
     f = getX(f1) ! Should I use this? 
     fp = getX(f1) ! Or this?
     fp => getX(f1) ! Or even this?
   enddo
   end program

目前,我正在Windows上运行。当我点击CTR-ALT-DLT并查看性能时,"物理内存使用率#34;每次循环迭代都会增加。这就是我假设我有内存泄漏的原因。

所以我想回答一下我的问题:这是内存泄漏吗? (内存随着上述每种情况而增加)。如果是这样,有没有办法在使用指针时避免内存泄漏?如果不是,那么发生了什么,我应该关注并且有办法减少这种行为的严重性吗?

对于最初模糊的问题,我们深表歉意。我希望这更加重要。

2 个答案:

答案 0 :(得分:1)

你真的受限于Fortran 90吗?在Fortran 2003中,您将使用可分配的函数结果。这更安全。使用指针函数结果,是否有此代码的内存泄漏取决于您引用该函数的方式,您不会显示该函数。如果必须从过程返回指针,则通过子例程参数返回它会更安全。

但是...

这个功能毫无意义。在之后测试这个%vals3D` 的关联状态没有必要,你已经将它作为上一行中SHAPE的参数引用了。如果指针组件被取消分配(或具有未定义的指针关联状态),则不允许您引用它。

此外,如果指针组件是关联的,那么你只需要调用stop!

也许你已经错误地将代码转录到了问题?


如果您只是删除以if (associated(this%vals3D))...开头的整个if结构,那么您的代码可能有意义。

但是...

  • 如果this%TF3D为真,则this%vals3D必须关联。
  • 引用该函数时,必须使用指针赋值

    array_ptr => getValues3D(foo)
    !          ^
    !          |
    !          + this little character is very important.
    

    忘掉那个小角色,你正在使用正常的作业。在语法上有效,难以在读取代码时选择差异,在这种情况下,除了使用指针的常见缺陷(例如,您需要DEALLOCATE)之外,可能是内存损坏或泄漏的源,直到最糟糕的时刻可能无法检测到在重用它之前的array_ptr或它超出范围)。这就是返回指针结果的函数被认为有风险的原因。


您的完整代码显示了几个内存泄漏。每次你分配一个POINTER的东西 - 你需要几乎保证匹配的DEALLOCATE。

您的测试代码中有一个循环。 ALLOCATE被大量调用 - 在两者的setter和getter中。匹配的DEALLOCATE语句在哪里?

答案 1 :(得分:0)

每次调用setX时,您类型的x组件的任何先前分配的内存都将被泄露。由于您调用该函数10 ^ 5次,您将浪费100000-1份。如果您知道 this%x的大小永远不会改变,只需检查以前的调用是否已经分配了内存,方法是检查ASSOCIATED(this%x)是否为真。如果是,请跳过分配并直接转到赋值语句。如果大小确实发生了变化,那么首先必须在分配新空间之前解除分配旧副本。

关于setX的另外两条小评论:虚拟参数TARGET的{​​{1}}属性似乎是多余的,因为你从不接受该参数的指针。其次,您的类型的x组件似乎也是多余的,因为您可以检查是否已分配TFx

对于函数x,为什么不完全跳过分配,只设置getX?不可否认,这将返回对基础数据的直接引用,这可能是您想要避免的。

在你的循环中,

   do i=1,10**5
     call setX(f1,f) ! 
     f = getX(f1) ! Should I use this? 
     fp = getX(f1) ! Or this?
     fp => getX(f1) ! Or even this?
   enddo

res => this%x将允许您获取指向您类型的基础fp => getX(f1)组件的指针(如果您采用上述更改)。另外两个使用赋值运算符,并将x的结果中的数据复制到getX或(如果先前已分配)f。如果未分配fp,则代码将崩溃。

如果您不想授予对基础数据的直接访问权限,那么我建议将fp的返回值定义为自动数组,其大小由getX确定。也就是说,您可以将函数编写为

   function getX(this) result(res)
     implicit none
     type(vecField1D),intent(in) :: this
     real(dpn),dimension(size(this%x,1)) :: res
     res = this%x
   end function