使用 move_alloc 和来源分配扩展可分配数组
Extending an allocatable array with move_alloc and sourced allocation
在下面的代码中,我试图通过首先分配一个更大的临时数组 buf(:)
来增加 a(:)
的长度,将 a(:)
的内容复制到 buf(:)
,然后使用move_alloc()
将数组描述符从buf
复制到a
:
program main
implicit none
integer, allocatable :: a(:), buf(:)
allocate( a(2) )
a = [1,2]
allocate( buf( 4 ), source= 0 ) !! (1)
buf( 1:2 ) = a( 1:2 ) !! (2)
! allocate( buf( 4 ), source= a ) !! (3)
! deallocate( a ) !! (4)
call move_alloc( buf, a )
print *, "a(:) = ", a(:)
end
在这里,我有两个问题:首先,在第 4 行中,是否有必要在调用 move_alloc()
... 之前显式释放 a(:)
?即使没有第 4 行,gfortran 和 Intel Fortran 似乎也能正常工作,但这是否意味着 move_alloc()
自动释放 a(:)
如果它是预分配的?其次,我们能否用第 3 行替换第 1 行和第 2 行,即使用具有不同长度数组的源分配?我已经对此进行了试验,而且 gfortran 和 Intel Fortran 似乎都接受了(显然)正确的结果。
Is it necessary to deallocate a(:)
:
更新 我误读了你的问题。您问的是 TO
部分。
我刚用 valgrind
试了一下,似乎 deallocate
不是防止泄漏所必需的。但我可能还是会这样做,只是为了安全起见。
第二个问题:
[Can we] ... use sourced allocation with different lengths of arrays?
根据我信任的 Fortran Book,没有:
[The] ... array being allocated must be conformable with (have the same rank and shape as) the source array or expression.
话又说回来,我的书不涵盖 2003 年之后的标准,因此 Fortran 2008 或 Fortran 2015 的情况可能有所不同。
从 Fortran 标准 (2008, 13.7.118) 关于 move_alloc
我们有参数的详细信息 to
(子例程的第二个参数)
It is an INTENT (OUT) argument
这与您在 link 中对 gfortran manual.
的描述相匹配
至于任何其他具有 intent(out)
和 allocatable
属性的虚拟参数,与 to
关联的实际参数将在调用子例程 move_alloc
时被释放。也就是说,您不需要自己解除分配 a
。
关于源分配,我们分配的数组必须与源数组一致,因此写作
allocate(buf(4), source=a) ! a is the same rank as buf, but extent 2
无效,和
一样
allocate(buf(4), source=a(1:2))
是。
然而,虽然有一些关于来源分配的编号限制,但其中一个不包含此符合性要求。因此,您的编译器不需要检测您的代码是否符合规范。
自然地,允许 编译器抱怨,正如您在使用 a(1:2)
作为源代码时看到的那样。在某种程度上,与 a
的情况相比,在编译时更容易看出 extent 4 的数组不符合 a(1:2)
。例如,您可以尝试 a(1:SIZE(a))
来查看您的编译器在此类测试中花费了多少精力。
作为最后的评论,当然可以用单一来源的分配替换您的第 1 行和第 2 行:
allocate(buf, source=[a,0,0]) ! Buf is 2 longer than a
但这不一定"better"。
编写 Fortran 标准是为了让您不必担心可分配的内存泄漏。如果一开始就没有禁止操作,应该不会造成任何泄漏。此规则适用于具有可分配变量的任何可能的符合标准的操作。
因此,正如 Intel 手册所述,to
参数将首先被释放。
在下面的代码中,我试图通过首先分配一个更大的临时数组 buf(:)
来增加 a(:)
的长度,将 a(:)
的内容复制到 buf(:)
,然后使用move_alloc()
将数组描述符从buf
复制到a
:
program main
implicit none
integer, allocatable :: a(:), buf(:)
allocate( a(2) )
a = [1,2]
allocate( buf( 4 ), source= 0 ) !! (1)
buf( 1:2 ) = a( 1:2 ) !! (2)
! allocate( buf( 4 ), source= a ) !! (3)
! deallocate( a ) !! (4)
call move_alloc( buf, a )
print *, "a(:) = ", a(:)
end
在这里,我有两个问题:首先,在第 4 行中,是否有必要在调用 move_alloc()
... 之前显式释放 a(:)
?即使没有第 4 行,gfortran 和 Intel Fortran 似乎也能正常工作,但这是否意味着 move_alloc()
自动释放 a(:)
如果它是预分配的?其次,我们能否用第 3 行替换第 1 行和第 2 行,即使用具有不同长度数组的源分配?我已经对此进行了试验,而且 gfortran 和 Intel Fortran 似乎都接受了(显然)正确的结果。
Is it necessary to deallocate
a(:)
:
更新 我误读了你的问题。您问的是 TO
部分。
我刚用 valgrind
试了一下,似乎 deallocate
不是防止泄漏所必需的。但我可能还是会这样做,只是为了安全起见。
第二个问题:
[Can we] ... use sourced allocation with different lengths of arrays?
根据我信任的 Fortran Book,没有:
[The] ... array being allocated must be conformable with (have the same rank and shape as) the source array or expression.
话又说回来,我的书不涵盖 2003 年之后的标准,因此 Fortran 2008 或 Fortran 2015 的情况可能有所不同。
从 Fortran 标准 (2008, 13.7.118) 关于 move_alloc
我们有参数的详细信息 to
(子例程的第二个参数)
It is an INTENT (OUT) argument
这与您在 link 中对 gfortran manual.
的描述相匹配至于任何其他具有 intent(out)
和 allocatable
属性的虚拟参数,与 to
关联的实际参数将在调用子例程 move_alloc
时被释放。也就是说,您不需要自己解除分配 a
。
关于源分配,我们
allocate(buf(4), source=a) ! a is the same rank as buf, but extent 2
无效,和
一样allocate(buf(4), source=a(1:2))
是。
然而,虽然有一些关于来源分配的编号限制,但其中一个不包含此符合性要求。因此,您的编译器不需要检测您的代码是否符合规范。
自然地,允许 编译器抱怨,正如您在使用 a(1:2)
作为源代码时看到的那样。在某种程度上,与 a
的情况相比,在编译时更容易看出 extent 4 的数组不符合 a(1:2)
。例如,您可以尝试 a(1:SIZE(a))
来查看您的编译器在此类测试中花费了多少精力。
作为最后的评论,当然可以用单一来源的分配替换您的第 1 行和第 2 行:
allocate(buf, source=[a,0,0]) ! Buf is 2 longer than a
但这不一定"better"。
编写 Fortran 标准是为了让您不必担心可分配的内存泄漏。如果一开始就没有禁止操作,应该不会造成任何泄漏。此规则适用于具有可分配变量的任何可能的符合标准的操作。
因此,正如 Intel 手册所述,to
参数将首先被释放。