Pointers Fortran 90函数返回指针

Pointers Fortran 90函数返回指针,pointers,memory,memory-management,fortran,fortran90,Pointers,Memory,Memory Management,Fortran,Fortran90,我看到这个问题: 被接受的答案让我质疑我是否安全地编写了以下函数(不允许内存泄漏) 当我运行代码时会显示此警告,但如果以前(针对此函数)设置了我的此%vals3D,是否应该将其关联?我目前遇到了内存错误,当我引入了一个新模块,其中包含了这个函数时,它们开始出现 非常感谢您的帮助 我觉得我不够具体。我想创建以下类,并知道如何在内存方面安全地实现该类。即: module vectorField_mod use constants_mod implicit none typ

我看到这个问题:

被接受的答案让我质疑我是否安全地编写了以下函数(不允许内存泄漏)

当我运行代码时会显示此警告,但如果以前(针对此函数)设置了我的
此%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并查看性能时,“物理内存使用历史记录”会随着每次循环迭代而增加。这就是为什么我假设我有内存泄漏

所以我想提出我的问题:这是内存泄漏吗?(上述每一种情况下,内存都会增加)。如果是这样的话,在仍然使用指针的情况下,有没有办法避免内存泄漏?如果没有,那么发生了什么,我应该担心吗?有没有办法降低这种行为的严重性


对于最初的模糊问题,我很抱歉。我希望这更切题。

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

但是

这个函数是没有意义的。在上一行将此%vals3D`作为SHAPE的参数引用之后,测试其关联状态没有意义。如果指针组件已解除关联(或具有未定义的指针关联状态),则不允许引用它

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

也许你把问题的代码转录错了


如果您只需删除以
If(关联(此%vals3D))…
开头的整个If构造,那么您的代码可能有意义

但是

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

    array_ptr => getValues3D(foo)
    !          ^
    !          |
    !          + this little character is very important.
    
    忘记那个小角色,你就使用正常的赋值。语法上有效,在读取代码时很难找出差异,在这种情况下,可能是内存损坏或泄漏的根源,可能在最坏的情况下才被发现,此外还有使用指针的常见陷阱(例如,在重用数组_ptr之前需要释放它或它超出范围)。这就是为什么返回指针结果的函数被认为是有风险的


您的完整代码显示了几个内存泄漏。每次你分配的东西都是指针——你需要保证会有一个匹配的释放


测试代码中有一个循环。ALLOCATE在setter和getter中都被大量调用。匹配的释放语句在哪里?

每次调用
setX
时,先前为您类型的
x
组件分配的任何内存都将泄漏。由于调用该函数10^5次,将浪费100000-1份副本。如果知道
此%x
的大小永远不会更改,只需通过检查
关联(此%x)
是否为真来检查上一次调用是否已分配内存。如果是,则跳过分配并直接移动到赋值语句。如果大小确实发生了变化,那么在分配新空间之前,您必须首先释放旧副本

关于
setX
的另外两个次要注释:伪参数
x
TARGET
属性显得多余,因为您从未使用该参数的指针。其次,您的类型的
TFx
组件似乎也是多余的,因为您可以检查
x
是否已分配

对于函数
getX
,为什么不完全跳过分配,只设置
res=>这个%x
?诚然,这将返回对底层数据的直接引用,这可能是您希望避免的

在你的循环中

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
我建议尽可能远离函数返回指针。它们非常容易出错。公平地说,子例程中的返回指针可以更安全地实现吗?我在下面的评论中提到,我必须使用指针。是的,使用子例程或Allocatables。我仅限于使用Fortran 90。Fortran 90中的派生数据类型中不允许使用和可分配数组。我同意,知道是否存在内存泄漏取决于我引用函数的方式,这是很有帮助的。我应该包括这个函数的实现,但它的作用只是充当一个getter函数。我植入了我发布的网站上的代码片段,发现警告出现了。你链接到的问题中的代码示例中没有函数,所以你不能只是“植入”代码。但除此之外-链接问题中的逻辑与代码中的逻辑不匹配-也许您混淆了派生类型中的函数结果和指针组件?我忘记接受这个问题的任何答案,我决定这个答案将我引向正确的方向:不要使用函数返回分配的指针;他们太危险了。就像我们在书中讨论的那样。再次感谢你。 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 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