導入: なぜALLOCATABLE引数が重要なのか
数値計算プログラムにおいて、データサイズが実行時に決まることは珍しくありません。これまでのFortranでは、配列のサイズを予測して大きめに確保したり、ポインタを使って複雑な管理を行ったりする必要がありました。しかし、ALLOCATABLE属性を持つ変数をそのまま引数として渡すことで、サブルーチン内でメモリの確保(ALLOCATE)や解放(DEALLOCATE)を自由に行えるようになります。これにより、メモリの無駄を省き、コードの可読性を劇的に向上させることが可能です。
基礎知識: ALLOCATABLE属性と引数渡しの仕組み
Fortranにおいて「ALLOCATABLE」とは、プログラムの実行中にメモリ領域を動的に確保・解放できる属性を指します。通常、サブルーチンに配列を渡す際は、あらかじめサイズが決まっている必要がありますが、この属性を引数に指定することで、呼び出し元とサブルーチン間で「メモリ確保の状態」を共有できます。
ポイントは、サブルーチン内での操作が呼び出し元の変数にも直接反映される点です。これにより、データ生成を専門に行う関数や、計算結果のサイズが未知のケースで非常に強力な武器となります。
実装/解決策: 正しい指定方法
サブルーチン側で引数を受け取る際は、以下のように宣言します。
subroutine sub(v)
real, allocatable, intent(inout) :: v(:)
end subroutine
ここで重要なのは「intent(inout)」を指定することです。メモリを確保(ALLOCATE)したり、既存のメモリを解放(DEALLOCATE)したりするためには、単なる入力ではなく、値の変更を許可する属性が必要です。
サンプルプログラム: 動的な配列生成の例
以下は、呼び出し元で未確保の配列を渡し、サブルーチン内で必要なサイズを確保する実用的なコード例です。
program main
implicit none
real, allocatable :: data(:)
! サブルーチンを呼び出し、メモリを確保してもらう
call allocate_data(data, 10)
! 確認
print , “確保されたサイズ:”, size(data)
! 使い終わったら解放
deallocate(data)
end program main
subroutine allocate_data(v, n)
integer, intent(in) :: n
real, allocatable, intent(inout) :: v(:)
! すでに確保済みなら一度解放する(安全のため)
if (allocated(v)) deallocate(v)
! 指定サイズでメモリを確保
allocate(v(n))
v = 1.0 ! 初期化などの処理
print , “サブルーチン内でメモリを確保しました。”
end subroutine
応用・注意点: 現場で役立つアドバイス
1. allocated関数でのチェック: ALLOCATEやDEALLOCATEを実行する前には、必ず「if (allocated(v))」を使って現在の状態を確認する習慣をつけましょう。既に確保されている変数に対して再度ALLOCATEを行うと、プログラムが異常終了(ランタイムエラー)します。
2. メモリリークの防止: 計算のループ内でALLOCATEを繰り返す場合、使い終わった配列は必ずDEALLOCATEするようにしてください。これを怠ると、メモリを消費し続け、大規模計算でメモリ不足の原因となります。
3. intentの指定: 呼び出し元に結果を反映させる必要がある場合は、必ずintent(inout)またはintent(out)を使用してください。これによって、コンパイラがメモリ管理の整合性をチェックしやすくなります。

コメント