Выделяемые (динамические) массивы#
Аттрибут allocatable
обеспечивает безопасный способ работы с памятью. По сравнению с переменными с атрибутом pointer
память управляется автоматически и будет автоматически освобождена, как только переменная выйдет за пределы области видимости. Использование allocatable
(выделяемых) переменных устраняет возможность создания утечек памяти в приложении.
Они могут быть использованы в процедурах для создания временных или рабочих массивов, в случаях, когда автоматические массивы были бы слишком большими, чтобы поместиться в стеке.
real(dp), allocatable :: temp(:)
allocate(temp(10))
Статус выделения памяти может быть проверен с помощью встроенной функции allocated
, чтобы избежать неинициализированного доступа
subroutine show_arr(arr)
integer, allocatable, intent(in) :: arr(:)
if (allocated(arr)) then
print *, arr
end if
end subroutine show_arr
Для выделения памяти переменным внутри подпрограммы фиктивный аргумент должен иметь атрибут allocatable
. Его использование в сочетании с атрибутом intent(out)
приведёт к освобождению памяти из предыдущих её выделений перед входом в подпрограмму:
subroutine foo(lam)
real(dp), allocatable, intent(out) :: lam(:)
allocate(lam(5))
end subroutine foo
Выделяемый (динамический) массив в дальнейшем может быть использован как обычный массив
real(dp), allocatable :: lam(:)
call foo(lam)
Для массива, для которого была выделена память, не может быть выделена память без предварительного освобождения выделенной ранее памяти. Аналогично, освобождение памяти может быть выполнено только для массивов, для которых она была выделена. Для повторного выделения памяти массиву используйте
if (allocated(lam)) deallocate(lam)
allocate(lam(10))
Передача выделяемых (динамических) массивов в подпрограммы больше не требует использования атрибута allocatable
для фиктивных аргументов.
subroutine show_arr(arr)
integer, intent(in) :: arr(:)
print *, arr
end subroutine show_arr
subroutine proc
integer :: i
integer, allocatable :: arr
allocate(arr(5))
do i = 1, size(arr)
arr(i) = 2*i + 1
end do
call show_arr(arr)
end subroutine proc
Передача массива с невыделенной памятью этом контексте приведёт к некорректному доступу к памяти. Выделяемые (динамические) массивы могут быть переданы как необязательные фиктивные аргументы –- если им не выделена память, то аргументы не будут учитываться. Атрибут allocatable
не ограничивается массивами и также может быть связан со скалярами, что может быть полезно в сочетании с необязательными фиктивными аргументами.
Выделенные области памяти могут быть перемещены между разными массивами, имеющими атрибут allocatable
, с помощью встроенной процедуры move_alloc
.
subroutine resize(var, n)
real(wp), allocatable, intent(inout) :: var(:)
integer, intent(in), optional :: n
integer :: this_size, new_size
integer, parameter :: inital_size = 16
if (allocated(var)) then
this_size = size(var, 1)
call move_alloc(var, tmp)
else
this_size = initial_size
end if
if (present(n)) then
new_size = n
else
new_size = this_size + this_size/2 + 1
end if
allocate(var(new_size))
if (allocated(tmp)) then
this_size = min(size(tmp, 1), size(var, 1))
var(:this_size) = tmp(:this_size)
end if
end subroutine resize
Наконец, выделение памяти не приводит к инициализации массива. Содержимое неинициализированного массива, скорее всего, представляет собой просто байты того, что ранее находилось по соответствующему адресу. Операция выделения памяти поддерживает инициализацию с помощью указания источника (source):
real(dp), allocatable :: arr(:)
allocate(arr(10), source=0.0_dp)
Ключевое слово source
поддерживает использование скаляров, переменных в виде массива значений и констант.