Matrizes Alocáveis#
O atributo allocatable
fornece um meio fácil para gerenciamento de memória. Em comparação à variáveis com o atributo pointer
, a memória é gerida automaticamente e será desalocada automaticamente assim que a variável sair de escopo. Usando variáveis alocáveis
remove a possibilidade de criar vazamentos de memória na aplicação.
Elas podem ser usadas para criar subrotinas para criar matrizes de rascunho ou trabalho, onde matrizes automáticas ficariam muito grandes para caber na stack.
real(dp), allocatable :: temp(:)
allocate(temp(10))
O status de alocação pode ser checado usando o intrínseco allocated
para evitar acessos não inicializados
subroutine show_arr(arr)
integer, allocatable, intent(in) :: arr(:)
if (allocated(arr)) then
print *, arr
end if
end subroutine show_arr
Para alocar variáveis dentro de um processo o argumento fictício tem que carregar o atributo allocatable
. Usando-o em combinação com intent(out)
irá desalocar alocações anteriores antes de entrar no processo:
subroutine foo(lam)
real(dp), allocatable, intent(out) :: lam(:)
allocate(lam(5))
end subroutine foo
A matriz alocada pode ser usada posteriormente como uma matriz normal
real(dp), allocatable :: lam(:)
call foo(lam)
Uma matriz já alocada não pode ser alocada novamente sem um desalocação anterior. Semelhante, desalocação só pode ser invocado em matrizes alocadas. Para realocar uma matriz use
if (allocated(lam)) deallocate(lam)
allocate(lam(10))
Passar matrizes alocadas para processos não requer mais o atributo allocatable
para os argumentos fictícios.
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
Passar uma matriz não alocada nesse contexto levará a um acesso de memória inválido. Matrizes alocáveis podem ser passadas para os argumentos fictícios optional
– se eles forem desalocados o argumento não estará presente. O atributo allocatable
não é limitado à matrizes e pode se associado com escalaras, o que pode ser útil em combinação com os argumentos fictícios optional
.
Alocações podem ser movidas entre diferentes matrizes com atributo allocatable
usando a subrotina intrínseca 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
Finalmente, alocações não inicializam a matriz. O conteúdo da matriz não inicializado é mais provável de ser bytes de qualquer coisa que esteja anteriormente no respectivo endereço. A alocação suporta inicialização usando o atributo da origem:
real(dp), allocatable :: arr(:)
allocate(arr(10), source=0.0_dp)
A palavra chave source
dá suporte à escalares e matrizes sejam variáveis ou constantes.