Fortran 函数返回可分配数组
Fortran function returning allocatable array
让我考虑一个返回 allocatable
数组的函数。保存结果的数组变量(在函数外)是否应该在赋值之前分配?
例如,考虑以下程序
program mem
implicit none
interface
function get_matrix() result(res)
real(kind=kind(0.d0)), allocatable :: res(:,:)
end function get_matrix
end interface
real(kind=kind(0.d0)), allocatable :: w(:,:)
allocate(w(2,2)) ! Is this necessary?
w=get_matrix()
deallocate(w)
end program mem
function get_matrix() result(res)
real(kind=kind(0.d0)), allocatable :: res(:,:)
allocate(res(2,2))
res = 0.d0
res(1, 1) = 1.d0
res(2, 2) = 1.d0
end function get_matrix
根据this, and ,为get_matrix
的结果分配的数组res
一旦超出范围就会被释放。
在主程序中对非分配变量 w
的赋值是否会延长 get_matrix
结果的范围?换句话说,如果我在主程序中省略 allocate(w(2,2))
,我会得到未定义的行为吗?
省略 allocate(w(2,2))
并使用 gfortran 9.2.0
和选项 -Wall -std=f2008
进行编译会给出以下警告
mem.f90:13:0:
13 | w=get_matrix()
|
Warning: ‘w.offset’ is used uninitialized in this function [-Wuninitialized]
mem.f90:13:0: Warning: ‘w.dim[0].lbound’ is used uninitialized in this function [-Wuninitialized]
mem.f90:13:0: Warning: ‘w.dim[0].ubound’ is used uninitialized in this function [-Wuninitialized]
mem.f90:13:0: Warning: ‘w.dim[1].lbound’ is used uninitialized in this function [-Wuninitialized]
mem.f90:13:0: Warning: ‘w.dim[1].ubound’ is used uninitialized in this function [-Wuninitialized]
mem.f90:13:0:
13 | w=get_matrix()
|
Warning: ‘w.dim[0].lbound’ may be used uninitialized in this function [-Wmaybe-uninitialized]
mem.f90:13:0: Warning: ‘w.dim[0].ubound’ may be used uninitialized in this function [-Wmaybe-uninitialized]
mem.f90:13:0: Warning: ‘w.dim[1].lbound’ may be used uninitialized in this function [-Wmaybe-uninitialized]
mem.f90:13:0: Warning: ‘w.dim[1].ubound’ may be used uninitialized in this function [-Wmaybe-uninitialized]
mem.f90:13:0: Warning: ‘w.dim[0].ubound’ may be used uninitialized in this function [-Wmaybe-uninitialized]
mem.f90:13:0: Warning: ‘w.dim[0].lbound’ may be used uninitialized in this function [-Wmaybe-uninitialized]
mem.f90:13:0: Warning: ‘w.dim[1].ubound’ may be used uninitialized in this function [-Wmaybe-uninitialized]
mem.f90:13:0: Warning: ‘w.dim[1].lbound’ may be used uninitialized in this function [-Wmaybe-uninitialized]
然而,运行带有valgrind
的程序以及用-fbounds-check
、-fsanitize=address
或-fsanitize=leak
编译的程序不会给出任何错误。此外,最后的指令 deallocate(w)
并没有使程序崩溃,这表明 w
包含 get_matrix
分配的内存,因此不需要分配 w
在主程序中。
同时,在代码中包含allocate(w(2,2))
会抑制编译器警告。尽管给人的印象是相同的内存被分配了两次,valgrind
并没有报告内存泄漏,事实上,报告的内存使用情况完全相同。
将 allocatable
数组存储为函数结果的正确方法是什么?
在存储get_matrix
的结果之前是否需要分配w
?
GCC bugzilla 中有许多类似的错误,它们被认为是您的编译器问题,而不是您的代码问题。有些已经修复,有些未修复 67679 66459 88455 以及更多(很多重复项)。
尝试最新版本的编译器,但它可能仍然存在。
作为解决方法,我使用-Wno-maybe-uninitialized
。
无需预分配或解除分配。编译器会处理这个。以下代码在 Intel fortran 中按预期工作。
program Console1
implicit none
! Variables
real(8), allocatable :: A(:,:)
integer :: i, j
! Body of Console1
A = get_matrix(6,4)
do i=1, size(A,1)
print '(*(g9.4),1x)', A(i,:)
end do
contains
function get_matrix(n,m) result(res)
integer, intent(in) :: n,m
real(8), allocatable :: res(:,:)
integer :: i
allocate(res(n,m))
res = 0d0
forall(i=1:min(n,m)) res(i,i)=1d0
end function
end program Console1
输出:
1.000 0.000 0.000 0.000
0.000 1.000 0.000 0.000
0.000 0.000 1.000 0.000
0.000 0.000 0.000 1.000
0.000 0.000 0.000 0.000
0.000 0.000 0.000 0.000
PS。使用 contains
关键字将函数放在程序声明中。这样它们就不是外部函数,也不需要接口声明。
ja72 和 Vladimir F 的回答是正确的。但是,为了完整起见,我将讨论另一点。在声明中
var = function_ref()
右边是对具有可分配结果的函数的引用,就可分配性质而言,实际上并没有什么特别之处。该表达式不是可分配的实体。
因此,我们的作业与其他作业非常相似
var = expr
右边是一个表达式。也就是说,从具有可分配结果的函数进行分配不需要特别考虑。 (当然,函数结果必须分配,但那是另一回事。)
在问题的情况下,通常的内在赋值规则适用。特别是,我们不需要在赋值之前分配w
。
开启
Furthermore, the instruction deallocate(w)
at the end does not crash the program, suggesting that w
contains the memory allocated by get_matrix
and, hence, one does not need to allocate w
in the main program.
又有话要说。 get_matrix
的函数结果本身在赋值中使用后被释放。 w
是一个独立于函数结果的实体,内部赋值导致 w
.
的分配
所以,不,你没有"prolong the scope of the result":你已经复制它到一个新分配的变量,然后在它完成后释放。考虑使用
这样的表达式
var = function_ref() + 1
同样,我们有一个表达式要赋值,但我们期望函数结果为 "persist" 吗?
还要考虑 。
让我考虑一个返回 allocatable
数组的函数。保存结果的数组变量(在函数外)是否应该在赋值之前分配?
例如,考虑以下程序
program mem
implicit none
interface
function get_matrix() result(res)
real(kind=kind(0.d0)), allocatable :: res(:,:)
end function get_matrix
end interface
real(kind=kind(0.d0)), allocatable :: w(:,:)
allocate(w(2,2)) ! Is this necessary?
w=get_matrix()
deallocate(w)
end program mem
function get_matrix() result(res)
real(kind=kind(0.d0)), allocatable :: res(:,:)
allocate(res(2,2))
res = 0.d0
res(1, 1) = 1.d0
res(2, 2) = 1.d0
end function get_matrix
根据this, and get_matrix
的结果分配的数组res
一旦超出范围就会被释放。
在主程序中对非分配变量 w
的赋值是否会延长 get_matrix
结果的范围?换句话说,如果我在主程序中省略 allocate(w(2,2))
,我会得到未定义的行为吗?
省略 allocate(w(2,2))
并使用 gfortran 9.2.0
和选项 -Wall -std=f2008
进行编译会给出以下警告
mem.f90:13:0:
13 | w=get_matrix()
|
Warning: ‘w.offset’ is used uninitialized in this function [-Wuninitialized]
mem.f90:13:0: Warning: ‘w.dim[0].lbound’ is used uninitialized in this function [-Wuninitialized]
mem.f90:13:0: Warning: ‘w.dim[0].ubound’ is used uninitialized in this function [-Wuninitialized]
mem.f90:13:0: Warning: ‘w.dim[1].lbound’ is used uninitialized in this function [-Wuninitialized]
mem.f90:13:0: Warning: ‘w.dim[1].ubound’ is used uninitialized in this function [-Wuninitialized]
mem.f90:13:0:
13 | w=get_matrix()
|
Warning: ‘w.dim[0].lbound’ may be used uninitialized in this function [-Wmaybe-uninitialized]
mem.f90:13:0: Warning: ‘w.dim[0].ubound’ may be used uninitialized in this function [-Wmaybe-uninitialized]
mem.f90:13:0: Warning: ‘w.dim[1].lbound’ may be used uninitialized in this function [-Wmaybe-uninitialized]
mem.f90:13:0: Warning: ‘w.dim[1].ubound’ may be used uninitialized in this function [-Wmaybe-uninitialized]
mem.f90:13:0: Warning: ‘w.dim[0].ubound’ may be used uninitialized in this function [-Wmaybe-uninitialized]
mem.f90:13:0: Warning: ‘w.dim[0].lbound’ may be used uninitialized in this function [-Wmaybe-uninitialized]
mem.f90:13:0: Warning: ‘w.dim[1].ubound’ may be used uninitialized in this function [-Wmaybe-uninitialized]
mem.f90:13:0: Warning: ‘w.dim[1].lbound’ may be used uninitialized in this function [-Wmaybe-uninitialized]
然而,运行带有valgrind
的程序以及用-fbounds-check
、-fsanitize=address
或-fsanitize=leak
编译的程序不会给出任何错误。此外,最后的指令 deallocate(w)
并没有使程序崩溃,这表明 w
包含 get_matrix
分配的内存,因此不需要分配 w
在主程序中。
同时,在代码中包含allocate(w(2,2))
会抑制编译器警告。尽管给人的印象是相同的内存被分配了两次,valgrind
并没有报告内存泄漏,事实上,报告的内存使用情况完全相同。
将 allocatable
数组存储为函数结果的正确方法是什么?
在存储get_matrix
的结果之前是否需要分配w
?
GCC bugzilla 中有许多类似的错误,它们被认为是您的编译器问题,而不是您的代码问题。有些已经修复,有些未修复 67679 66459 88455 以及更多(很多重复项)。
尝试最新版本的编译器,但它可能仍然存在。
作为解决方法,我使用-Wno-maybe-uninitialized
。
无需预分配或解除分配。编译器会处理这个。以下代码在 Intel fortran 中按预期工作。
program Console1
implicit none
! Variables
real(8), allocatable :: A(:,:)
integer :: i, j
! Body of Console1
A = get_matrix(6,4)
do i=1, size(A,1)
print '(*(g9.4),1x)', A(i,:)
end do
contains
function get_matrix(n,m) result(res)
integer, intent(in) :: n,m
real(8), allocatable :: res(:,:)
integer :: i
allocate(res(n,m))
res = 0d0
forall(i=1:min(n,m)) res(i,i)=1d0
end function
end program Console1
输出:
1.000 0.000 0.000 0.000
0.000 1.000 0.000 0.000
0.000 0.000 1.000 0.000
0.000 0.000 0.000 1.000
0.000 0.000 0.000 0.000
0.000 0.000 0.000 0.000
PS。使用 contains
关键字将函数放在程序声明中。这样它们就不是外部函数,也不需要接口声明。
ja72 和 Vladimir F 的回答是正确的。但是,为了完整起见,我将讨论另一点。在声明中
var = function_ref()
右边是对具有可分配结果的函数的引用,就可分配性质而言,实际上并没有什么特别之处。该表达式不是可分配的实体。
因此,我们的作业与其他作业非常相似
var = expr
右边是一个表达式。也就是说,从具有可分配结果的函数进行分配不需要特别考虑。 (当然,函数结果必须分配,但那是另一回事。)
在问题的情况下,通常的内在赋值规则适用。特别是,我们不需要在赋值之前分配w
。
开启
Furthermore, the instruction
deallocate(w)
at the end does not crash the program, suggesting thatw
contains the memory allocated byget_matrix
and, hence, one does not need to allocatew
in the main program.
又有话要说。 get_matrix
的函数结果本身在赋值中使用后被释放。 w
是一个独立于函数结果的实体,内部赋值导致 w
.
所以,不,你没有"prolong the scope of the result":你已经复制它到一个新分配的变量,然后在它完成后释放。考虑使用
这样的表达式var = function_ref() + 1
同样,我们有一个表达式要赋值,但我们期望函数结果为 "persist" 吗?
还要考虑