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" 吗?

还要考虑