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
- 引用函数时,必须使用指针赋值
忘记那个小角色,你就使用正常的赋值。语法上有效,在读取代码时很难找出差异,在这种情况下,可能是内存损坏或泄漏的根源,可能在最坏的情况下才被发现,此外还有使用指针的常见陷阱(例如,在重用数组_ptr之前需要释放它或它超出范围)。这就是为什么返回指针结果的函数被认为是有风险的array_ptr => getValues3D(foo) ! ^ ! | ! + this little character is very important.
您的完整代码显示了几个内存泄漏。每次你分配的东西都是指针——你需要保证会有一个匹配的释放
测试代码中有一个循环。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