Я написал свою первую программу с использованием allocatable. Работает как положено. Но так ли это на самом деле? И что еще более важно, как я могу настроить юнит-тест для обнаружения утечек памяти?
Идея программы заключается в том, чтобы сначала выделить кусок памяти для моего списка объектов. И каждый раз, когда я добавляю в список на один элемент больше, чем выделенный размер, я удваиваю распределение. Я делаю это, чтобы уменьшить количество выделений и последующее копирование данных из старой выделенной памяти во вновь выделенную память.
Я мог бы усложнить это, но сейчас я хотел бы потратить некоторое время на понимание ловушек, вместо того, чтобы падать головой в них через год или два в проект.
Ода скомпилирована с gfortran 8.3.0 на linux. И с помощью pFUnit 4.1. Приведенный ниже код является выдержкой для проверки только части выделения.
Вот моя тестовая программа:
program test_realloc
use class_test_malloc
integer :: i
real :: x, y
type(tmalloc) :: myobject
call myobject%initialize()
do i=1, 100
x = i * i
y = sqrt(x)
call myobject%add_nbcell(i, x, y)
end do
call myobject%dump()
end program test_realloc
array_reallocation.f:
!
! Simple test to see if my understanding of dynamicly allocation
! of arrays is correct.
!
module class_test_malloc
use testinglistobj
implicit none
type tmalloc
integer :: numnbcells, maxnbcells
type(listobj), allocatable :: nbcells(:)
contains
procedure, public :: initialize => init
procedure, public :: add_nbcell ! Might be private?
procedure, private :: expand_nbcells
procedure, public :: dump
end type tmalloc
contains
subroutine init(this)
class(tmalloc), intent(inout) :: this
this%numnbcells = 0
this%maxnbcells = 4
allocate (this%nbcells(this%maxnbcells))
end subroutine init
subroutine add_nbcell(this, idx, x, y)
class(tmalloc), intent(inout) :: this
integer, intent(in) :: idx
real, intent(in) :: x, y
type(listobj) :: nbcell
if(this%numnbcells .eq. this%maxnbcells) then
call this%expand_nbcells()
print *,"Expanding"
endif
this%numnbcells = this%numnbcells + 1
nbcell%idx = idx
nbcell%x = x
nbcell%y = y
this%nbcells(this%numnbcells) = nbcell
print *,"Adding"
end subroutine add_nbcell
subroutine expand_nbcells(this)
class(tmalloc), intent(inout) :: this
type(listobj), allocatable :: tmpnbcells(:)
integer :: size
size = this%maxnbcells *2
allocate (tmpnbcells(size))
tmpnbcells(1:this%maxnbcells) = this%nbcells
call move_alloc( from=tmpnbcells, to=this%nbcells)
this%maxnbcells = size
end subroutine
subroutine dump(this)
class(tmalloc), intent(inout) :: this
integer :: i
do i=1, this%numnbcells
print*, this%nbcells(i)%x, this%nbcells(i)%y
end do
end subroutine
end module
listobj.f :
module testinglistobj
type listobj
integer :: idx
real :: x
real :: y
end type
end module testinglistobj