9.3 割付け拡張
Fortran 2003では ALLOCATABLE 属性が局所変数のみならず成分、仮変数、 関数結果に対しても指定できるようになりました。 これはISO Technical Report ISO/IEC TR 15581:1999に説明される通りです。
また、MOVE_ALLOC 組込み手続き及び代入においての自動再割付けが追加 されました。
9.3.1 割付け仮配列 [4.x]
仮引数は割付け配列として宣言可能です。例:
SUBROUTINE s(dum)
REAL,ALLOCATABLE :: dum(:,:)
...
END SUBROUTINE
割付け仮引数を持つということは、どのような参照に対しても明示的な引用仕様が 必要であることを意味します。すなわち手続きが内部手続きもしくはモジュール手 続きでない場合には、その手続きを参照するすべてのルーチンにおいて参照可能な 引用仕様ブロックが必要です。
割付け仮配列に渡されるどのような実引数もまた割付け配列でなければなりません。
それは更に同じ型、種別型パラメタ、次元数を持っていなくてはなりません。
例:
REAL,ALLOCATABLE :: x(:,:) CALL s(x)
実引数(引数の割付けもしくは解放を行うものも含む)は手続き呼出し前に
割付けられている必要はありません。
例:
PROGRAM example2
REAL,ALLOCATABLE :: x(:,:)
OPEN(88,FILE='myfile',FORM='unformatted')
CALL read_matrix(x,88)
!
... process x in some way
!
REWIND(88)
CALL write_and_delete_matrix(x,88)
END
!
MODULE module
CONTAINS
!
! This procedure reads the size and contents of an array from an
! unformatted unit.
!
SUBROUTINE read_matrix(variable,unit)
REAL,ALLOCATABLE,INTENT(OUT) :: variable(:,:)
INTEGER,INTENT(IN) :: unit
INTEGER dim1,dim2
READ(unit) dim1,dim2
ALLOCATE(variable(dim1,dim2))
READ(unit) variable
CLOSE(unit)
END SUBROUTINE
!
! This procedures writes the size and contents of an array to an
! unformatted unit, and then deallocates the array.
!
SUBROUTINE write_and_delete_matrix(variable,unit)
REAL,ALLOCATABLE,INTENT(INOUT) :: variable(:,:)
INTEGER,INTENT(IN) :: unit
WRITE(unit) SIZE(variable,1),SIZE(variable,2)
WRITE(unit) variable
DEALLOCATE(variable)
END SUBROUTINE
END
9.3.2 割付け関数結果 [4.x]
関数の結果は割付け配列として宣言可能です。例:
FUNCTION af() RESULT(res)
REAL,ALLOCATABLE :: res
関数の呼び出しにおいて、結果変数は解放されます。それは関数から戻る前に
割付けられている必要があります。
例:
!
! The result of this function is the original argument with adjacent
! duplicate entries deleted (so if it was sorted, each element is unique).
!
FUNCTION compress(array)
INTEGER,ALLOCATABLE :: compress(:)
INTEGER,INTENT(IN) :: array(:)
IF (SIZE(array,1)==0) THEN
ALLOCATE(compress(0))
ELSE
N = 1
DO I=2,SIZE(array,1)
IF (array(I)/=array(I-1)) N = N + 1
END DO
ALLOCATE(compress(N))
N = 1
compress(1) = array(1)
DO I=2,SIZE(array,1)
IF (array(I)/=compress(N)) THEN
N = N + 1
compress(N) = array(I)
END IF
END DO
END IF
END
割付け配列の結果は使用後に自動的に解放されます。
9.3.3 割付け構造体成分 [4.x]
構造体成分は割付けとして宣言可能です。例:
MODULE matrix_example
TYPE MATRIX
REAL,ALLOCATABLE :: value(:,:)
END TYPE
END MODULE
割付け配列変数と同様に割付け配列成分は最初に割付けられてはいません。
割付け成分を持つ変数を含む手続きから抜け出す際にすべての割付け成分は
自動的に解放されます。これはポインタ成分の場合(ポインタ成分は自動的
に解放されません)と異なる点です。
例:
SUBROUTINE sub(n,m)
USE matrix_example
TYPE(matrix) a,b,c
!
! a%value, b%value and c%value are all unallocated at this point.
!
ALLOCATE(a%value(n,m),b%value(n,m))
!
... do some computations, then
!
RETURN
!
! Returning from the procedure automatically deallocates a%value, b%value,
! and c%value (if they are allocated).
!
END
割付け配列成分を持つ変数を解放する場合その成分が先に解放されます。
この動作は再帰的に行われ、すべての割付け副オブジェクトがメモリリークすること
なく解放されます。
既に割付けられた関数結果の割付け成分はいずれもその結果が使用された後に自動的に 解放されます。
PROGRAM deallocation_example
TYPE inner
REAL,ALLOCATABLE :: ival(:)
END TYPE
TYPE outer
TYPE(inner),ALLOCATABLE :: ovalue(:)
END TYPE
TYPE(outer) x
!
! At this point, x%ovalue is unallocated
!
ALLOCATE(x%ovalue(10))
!
! At this point, x%ovalue(i)%ival are unallocated, i=1,10
!
ALLOCATE(x%ovalue(2)%ival(1000),x%ovalue(5)%ival(9999))
!
! Only x%ovalue(2)%ival and x%ovalue(5)%ival are allocated
!
DEALLOCATE(x%ovalue)
!
! This has automatically deallocated x%ovalue(2)%ival and x%ovalue(5)%ival
!
END
このような型の構造体構成子内において、割付け配列成分に対応する式としては次のもの
が可能です。
- NULL()組込み関数(割付けられていない配列を表す)
- 割付けられている、もしくは割付けられていない割付け配列
- その他の配列式(割付けられた配列を示す)
SUBROUTINE constructor_example
USE matrix_example
TYPE(matrix) a,b,c
REAL :: array(10,10) = 1
REAL,ALLOCATABLE :: alloc_array(:,:)
a = matrix(NULL())
!
! At this point, a%value is unallocated
!
b = matrix(array*2)
!
! Now, b%value is a (10,10) array with each element equal to 2.
!
c = matrix(alloc_array)
!
! Now, c%value is unallocated (because alloc_array was unallocated).
!
END
このような型の組込み代入は割付け配列成分の“深いコピー”を行います。 割付け配列成分は一旦解放されたかのようなもので、次に式の成分が割付けられ ていた場合には、変数の成分が正しい大きさに割付けられ、値がコピーされます。
SUBROUTINE assignment_example
USE matrix_example
TYPE(matrix) a,b
!
! First we establish a value for a
!
ALLOCATE(a%value(10,20))
a%value(3,:) = 30
!
! And a value for b
!
ALLOCATE(b%value(1,1))
b%value = 0
!
! Now the assignment
!
b = a
!
! The old contents of b%value have been deallocated, and b%value now has
! the same size and contents as a%value.
!
END
9.3.4 割付け成分の例
これは多項演算機能を提供する簡単なモジュールの定義とその用例を示したものです。 これを行うために割付け成分の組込み代入と自動的に提供される構造体構成子を利用 し、加算演算子(+)を定義します。より完成されたモジュールでは乗算等の他の演算子 も提供されることになるでしょう。
!
! Module providing a single-precision polynomial arithmetic facility
!
MODULE real_poly_module
!
! Define the polynomial type with its constructor.
! We will use the convention of storing the coefficients in the normal
! order of highest degree first, thus in an N-degree polynomial, COEFF(1)
! is the coefficient of X**N, COEFF(N) is the coefficient of X**1, and
! COEFF(N+1) is the scalar.
!
TYPE,PUBLIC :: real_poly
REAL,ALLOCATABLE :: coeff(:)
END TYPE
!
PUBLIC OPERATOR(+)
INTERFACE OPERATOR(+)
MODULE PROCEDURE rp_add_rp,rp_add_r,r_add_rp
END INTERFACE
!
CONTAINS
TYPE(real_poly) FUNCTION rp_add_r(poly,real)
TYPE(real_poly),INTENT(IN) :: poly
REAL,INTENT(IN) :: real
INTEGER isize
IF (.NOT.ALLOCATED(poly%coeff)) STOP 'Undefined polynomial value in +'
isize = SIZE(poly%coeff,1)
rp_add_r%coeff(isize) = poly%coeff(isize) + real
END FUNCTION
TYPE(real_poly) FUNCTION r_add_rp(real,poly)
TYPE(real_poly),INTENT(IN) :: poly
REAL,INTENT(IN) :: real
r_add_rp = rp_add_r(poly,real)
END FUNCTION
TYPE(real_poly) FUNCTION rp_add_rp(poly1,poly2)
TYPE(real_poly),INTENT(IN) :: poly1,poly2
INTEGER I,N,N1,N2
IF (.NOT.ALLOCATED(poly1%coeff).OR..NOT.ALLOCATED(poly2%coeff)) &
STOP 'Undefined polynomial value in +'
! Set N1 and N2 to the degrees of the input polynomials
N1 = SIZE(poly1%coeff) - 1
N2 = SIZE(poly2%coeff) - 1
! The result polynomial is of degree N
N = MAX(N1,N2)
ALLOCATE(rp_add_rp%coeff(N+1))
DO I=0,MIN(N1,N2)
rp_add_rp%coeff(N-I+1) = poly1%coeff(N1-I+1) + poly2%coeff(N2-I+1)
END DO
! At most one of the next two DO loops is ever executed
DO I=N1+1,N
rp_add_rp%coeff(N-I+1) = poly2%coeff(N2-I+1)
END DO
DO I=N2+1,N
rp_add_rp%coeff(N-I+1) = poly1%coeff(N1-I+1)
END DO
END FUNCTION
END MODULE
!
! Sample program
!
PROGRAM example
USE real_poly_module
TYPE(real_poly) p,q,r
p = real_poly((/1.0,2.0,4.0/)) ! x**2 + 2x + 4
q = real_poly((/1.0,-5.5/)) ! x - 5.5
r = p + q ! x**2 + 3x - 1.5
print 1,'The coefficients of the answer are:',r%coeff
1 format(1x,A,3F8.2)
END
上記例を実行すると以下の出力が得られます:
The coefficients of the answer are: 1.00 3.00 -1.50
9.3.5 MOVE_ALLOC組込みサブルーチン [5.2]
このサブルーチンは割付けを一つの割付け変数から他の割付け変数へ移動します。 これは割付け配列を一回のコピー操作だけで拡張する上で使用でき、新しい配列に おいて値がどこに行くべきかの制御を可能にします。例:
REAL,ALLOCATABLE :: a(:),tmp(:) ... ALLOCATE(a(n)) ... ! Here we want to double the size of A, without losing any of the values ! that are already stored in it. ALLOCATE(tmp(size(a)*2)) tmp(1:size(a)) = a CALL move_alloc(from=tmp,to=a) ! TMP is now deallocated, and A has the new size and values.値をどこか別の場所に格納するには代入文を変更してください。例えばすべてを 終端に移動するには次のように記述します:
tmp(size(a)+1:size(a)*2) = a
9.3.6 割付けスカラ [5.2]
ALLOCATABLE属性は配列のみではなく新たにスカラ変数と成分にも適用できるよう になりました。 これは多相性(CLASS)もしくは無指定型パラメタ (例:CHARACTER(:))もしくはその両方と共に使うときにとても便利です。 詳細については“型付き割付け ”、 “元指定割付け ”、 “自動再割付け ”のセクションをご参照下 さい。9.3.7 自動再割付け [5.2]
割付け配列全体への代入において、代入される式が異なる大きさもしくは形状の 配列であった場合には、割付け配列は再割付けされ正しい形状になります (Fortran95ではこのような代入はエラーとなります)。例:
ALLOCATE(a(10)) ... a = (/ (i,i=1,100) /) ! A is now size 100
同様に、割付け変数が無指定型パラメタ(後のセクションで説明されます)を持つ場合 で、かつ割付けが行われていないかもしくは式と異なる値を持つ場合には、割付け変数 は再割付けされてその型パラメタと同じ値を持つようになります。 これにより真の可変長文字変数が可能となります。
CHARACTER(:),ALLOCATABLE :: name ... name = 'John Smith' ! LEN(name) is now 10, whatever it was before. name = '?' ! LEN(name) is now 1.割付けオブジェクトの副オブジェクトはそれ自体割付けではないため、この自動再割付け を文字部分列(文字の場合)、あるいは部分配列(配列の場合)を用いて抑止することが できる点に注意ください。
例:
name(:) = '?' ! Normal assignment with truncation/padding. a(:) = (/ (i,i=1,100) /) ! Asserts that A is already of size 100.
