使用 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 参数将首先被释放。