使用move_alloc和sourced allocation扩展可分配数组

时间:2015-11-25 00:54:19

标签: arrays fortran allocation

在下面的代码中,我试图通过首先分配更大的临时数组a(:)来增加buf(:)的长度,将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行中,是否有必要在调用a(:)之前明确解除move_alloc() ...?即使没有第4行,gfortran和英特尔Fortran似乎都能正常工作,但这是否意味着move_alloc()如果预先分配了a(:)会自动解除分配?{1}}?其次,我们可以将第1行和第2行替换为3,即使用具有不同长度数组的源分配吗?我已经对此进行了实验,而且,gfortran和英特尔Fortran似乎都接受了(显然)正确的结果。

3 个答案:

答案 0 :(得分:3)

根据Fortran标准(2008年,13.7.118)关于move_alloc,我们有参数to的细节(子例程的第二个参数)

  

这是一个INTENT(OUT)参数

与您在gfortran manual的链接中提供的说明相匹配。

对于具有intent(out)allocatable属性的任何其他伪参数,与to关联的实际参数将在调用子例程move_alloc时被释放。也就是说,您不需要自己解除a

关于源分配,我们already know分配的数组必须与源数组一致,以便编写

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)作为源时所看到的那样。在某种程度上,在编译时更容易看到范围4的数组与a(1:2)不符合a的情况。您可以尝试使用a(1:SIZE(a))进行试验,以了解编译器在此类测试中花费了多少精力。

作为最终评论,当然可以使用单一来源分配来替换第1行和第2行:

allocate(buf, source=[a,0,0])  ! Buf is 2 longer than a

但这并不一定“更好”。

答案 1 :(得分:2)

编写Fortran标准,以便您不必了解可分配内存泄漏。如果首先不禁止操作,则不应导致任何泄漏。此规则适用于任何可能的标准符合操作和可分配变量。

因此,正如英特尔手册所述,to参数将首先被解除分配。

答案 2 :(得分:1)

  

是否有必要解除分配a(:)

更新我误读了您的问题。您在询问TO部分。

我刚用valgrind尝试过,似乎deallocate似乎没有必要防止泄漏。但我可能仍然会这样做,只是为了安全起见。

第二个问题:

  

[我们可以] ......使用不同长度数组的源分配吗?

根据我信任的Fortran Book,没有:

  

[...] ...分配的数组必须与源数组或表达式一致(具有相同的等级和形状)。

然而,我的书还没有涵盖2003年以后的标准,因此Fortran 2008或Fortran 2015的情况可能会有所不同。