分配具有自身值的可分配数组

Assignment of allocatable array with itself values

我想知道在现代 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

这段代码给出了 ifort 18 的正确答案,returns "Segmentation fault" 和 gfortran 7.4。

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

注意:在线程 checking for self-assignment in fortran overloaded assignment 中,@IanH 区分了 call assign(a,a)call assign(a,(a)) 但我相信它不能解决这个问题,因为我有可分配的参数。

注意:在线程 Automatic array allocation upon assignment in Fortran 中,@francescalus 解释了内部分配的自动分配,但我再次认为它不适用于此处。

这次通话

call assign(a, a(1))

被 Fortran 的别名规则所禁止。您在不同的参数中传递了相同的值,pointertarget 都不是,您正在修改其中之一。

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

中使用 b
a(1) = b

这肯定会失败,因为它指向一些未定义的内存。您对 Intel Fortran 很幸运,但您的代码是非法的。也许 Intell 将新 a 分配到了旧 a 所在的同一位置,但这纯属运气。

如果你这样做,它会起作用

type(t), allocatable, intent(inout) :: a(:) 
type(t),              value  :: b
deallocate(a)
allocate(a(1))
a(1) = b

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

可以使用同一数组的数组元素分配给可分配数组。例如,对于 a 可分配

a = [a(2), a(1)]

有效且具有预期结果。无论 a 是内部类型(对于内部赋值)还是派生类型(对于内部或定义赋值),这都是相同的。在左侧受到影响之前,右侧被视为完全计算为表达式。

但是,使用 call assign(a,a(1)) 与此赋值不同。

您引用的 IanH 的回答中的观点与此相关。定义的赋值类似于 call assign(a,(a(1))) 而不是 call assign(a,a(1)).

这很重要,因为 Vladimir F 的回答中提到了别名限制,我不会重复。使用 call assign(a,(a(1))) 删除别名,因为 (a(1)) 是一个表达式,其值为数组元素而不是数组元素本身。这类似于 Vladimir F 提到的 value 属性,但没有创建可定义的实体。

定义的赋值使用 (rhs) 结构来避免这种别名问题。

关于您的 gfortran 结果,IanH 创建了一个 bug report for GCC 来回答另一个问题。它可能与解释您在这里遇到的惊喜有关。