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.