分配具有自身值的可分配数组
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 的别名规则所禁止。您在不同的参数中传递了相同的值,pointer
或 target
都不是,您正在修改其中之一。
然后,编译器取消分配 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 来回答另一个问题。它可能与解释您在这里遇到的惊喜有关。
我想知道在现代 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 的别名规则所禁止。您在不同的参数中传递了相同的值,pointer
或 target
都不是,您正在修改其中之一。
然后,编译器取消分配 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 来回答另一个问题。它可能与解释您在这里遇到的惊喜有关。