fortran66のブログ

fortran について書きます。

【メモ帳】deep copy / shallow copy

Fortran の派生型中の動的割り付け成分の代入時の動作差

派生型中に、動的な配列を定義することができますが、allocatable で定義するか、pointer で定義するかで、代入時のコピーのされ方に違いが出ます。

allocatable の場合は、内容丸ごとコピーですが、これに対して pointer の場合は、(当然ですが)動的に確保した記憶領域の番地情報だけがコピーされます。つまり allocatable の場合は deep copy 、pointer の場合は shallow copy となります。

したがって、pointer で確保した場合は、派生型内の動的配列の実体は一つなのでその内容をいじると、代入した他の派生型変数でもその内容が変化します。一方、allocatble の場合、動的配列は新しく確保されて内容が写されるので変化しません。

代入コストから考えると pointer の場合はコストが小さいですが、allocatable の場合は新たにメモリー領域を確保したうえで内容を写し取るので、コストが大きいと言えます。

実行結果

 allocatable component : deep copy
          10           1           2           3           4
          10           1           2           3           4
          10         101         102         103         104
          10           1           2           3           4
 
 pointer     component : shallow copy
          10           4           3           2           1
          10           4           3           2           1
          10         100          99          98          97
          10         100          99          98          97

プログラム

        program test
            implicit none
            type :: t_alloc
                integer :: n
                integer, allocatable :: ia(:)
            end type t_alloc
    
            type t_point
                integer :: n
                integer, pointer :: ip(:)
            end type t_point
        
            type (t_alloc) :: a, b
            type (t_point) :: p, q
            a = t_alloc(10, [1, 2, 3, 4])
            b = a
            !
            print *, 'allocatable component : deep copy' 
            print *, a%n, a%ia
            print *, b%n, b%ia
            a%ia = [101, 102, 103, 104]
            print *, a%n, a%ia
            print *, b%n, b%ia
            !
            print *
            print *, 'pointer     component : shallow copy' 
            p%n = 10
            allocate(p%ip(4), source = [4, 3, 2, 1])
            q = p
            print *, p%n, p%ip
            print *, q%n, q%ip
            p%ip = [100, 99, 98, 97]
            print *, p%n, p%ip
            print *, q%n, q%ip
        end program test

Modern Fortran Explained: Incorporating Fortran 2018 (Numerical Mathematics and Scientific Computation)

Modern Fortran Explained: Incorporating Fortran 2018 (Numerical Mathematics and Scientific Computation)