可分配数组及其自身值的分配

fra*_*ena 1 fortran variable-assignment allocatable-array

我想知道在现代 Fortran 中是否可以使用其本身或其中的一部分来分配可分配数组来执行此操作。这是一个简单的例子:

module modu
implicit none

type :: t
  integer :: i
end type

contains

subroutine assign(a,b)
type(t), allocatable, intent(out) :: a(:) 
type(t),              intent(in)  :: b
allocate(a(1))
a(1) = b
end subroutine
end module

!----------------------

program test
use modu
implicit none
type(t), allocatable :: a(:)

allocate(a(1))
a(1)%i = 2
call assign(a, a(1))
print*, a(1)%i
end program
Run Code Online (Sandbox Code Playgroud)

此代码使用 ifort 18 给出正确的答案,并使用 gfortran 7.4 返回“分段错误”。

注意:原来的问题有点复杂,因为call assign(a, a(1))应该call assign(a, a(1)+b)用运算符 + 正确重载来替换,但结论(尊重 ifort 和 gfortran)是相同的。

注意:在fortran 重载赋值中检查自赋值的线程中,@IanH 区分了call assign(a,a)call assign(a,(a)),但我相信它不能解决这个问题,因为我有可分配的参数。

注意:在Fortran 中分配时的自动数组分配线程中,@francescalus 解释了内部分配时的自动分配,但我再次相信它不适用于此处。

Vla*_*r F 6

这个电话

call assign(a, a(1))
Run Code Online (Sandbox Code Playgroud)

Fortran 的别名规则禁止使用。您在不同的参数中传递相同的值,但两者都不是pointertarget,并且您正在修改其中之一。

然后,编译器会取消分配,a因为它是intent(out). 这意味着旧的a(1)已经不复存在了。但b仍然指出那里。a然后你在其他地方分配一个新的。然后你尝试b使用

a(1) = b
Run Code Online (Sandbox Code Playgroud)

这肯定会失败,因为它指向一些未定义的内存。您只是幸运地使用了 Intel Fortran,但您的代码是非法的。也许英特尔将新设备分配a到旧设备所在的位置a,但这纯粹是运气。

如果你这样做就会起作用

type(t), allocatable, intent(inout) :: a(:) 
type(t),              value  :: b
deallocate(a)
allocate(a(1))
a(1) = b
Run Code Online (Sandbox Code Playgroud)

我不确定为什么它会因intent(out)和 而崩溃value。这可能是编译器的问题,报告为bug 92178