Let me consider a function returning an allocatable array. Should the array variable holding the result (outside the function) be allocated before an assignment?
Consider, e.g., the following program
program mem
implicit none
interface
function get_matrix() result(res)
real(kind=kind(0.d0)), allocatable :: res(:,:)
end function get_matrix
end interface
real(kind=kind(0.d0)), allocatable :: w(:,:)
allocate(w(2,2)) ! Is this necessary?
w=get_matrix()
deallocate(w)
end program mem
function get_matrix() result(res)
real(kind=kind(0.d0)), allocatable :: res(:,:)
allocate(res(2,2))
res = 0.d0
res(1, 1) = 1.d0
res(2, 2) = 1.d0
end function get_matrix
According to this, and this, the array res allocated for the result of get_matrix is deallocated as soon as it goes out of scope.
Would an assignment to a non-allocated variable w in the main program prolong the scope of the result of get_matrix? In other words, if I omit allocate(w(2,2)) in the main program, do I get an undefined behavior?
Omitting allocate(w(2,2)) and compiling with gfortran 9.2.0 and options -Wall -std=f2008 gives following warnings
mem.f90:13:0:
13 | w=get_matrix()
|
Warning: ‘w.offset’ is used uninitialized in this function [-Wuninitialized]
mem.f90:13:0: Warning: ‘w.dim[0].lbound’ is used uninitialized in this function [-Wuninitialized]
mem.f90:13:0: Warning: ‘w.dim[0].ubound’ is used uninitialized in this function [-Wuninitialized]
mem.f90:13:0: Warning: ‘w.dim[1].lbound’ is used uninitialized in this function [-Wuninitialized]
mem.f90:13:0: Warning: ‘w.dim[1].ubound’ is used uninitialized in this function [-Wuninitialized]
mem.f90:13:0:
13 | w=get_matrix()
|
Warning: ‘w.dim[0].lbound’ may be used uninitialized in this function [-Wmaybe-uninitialized]
mem.f90:13:0: Warning: ‘w.dim[0].ubound’ may be used uninitialized in this function [-Wmaybe-uninitialized]
mem.f90:13:0: Warning: ‘w.dim[1].lbound’ may be used uninitialized in this function [-Wmaybe-uninitialized]
mem.f90:13:0: Warning: ‘w.dim[1].ubound’ may be used uninitialized in this function [-Wmaybe-uninitialized]
mem.f90:13:0: Warning: ‘w.dim[0].ubound’ may be used uninitialized in this function [-Wmaybe-uninitialized]
mem.f90:13:0: Warning: ‘w.dim[0].lbound’ may be used uninitialized in this function [-Wmaybe-uninitialized]
mem.f90:13:0: Warning: ‘w.dim[1].ubound’ may be used uninitialized in this function [-Wmaybe-uninitialized]
mem.f90:13:0: Warning: ‘w.dim[1].lbound’ may be used uninitialized in this function [-Wmaybe-uninitialized]
However, running the program with valgrind, as well as compiling with -fbounds-check, -fsanitize=address, or -fsanitize=leak does not give any error. Furthermore, the instruction deallocate(w) at the end does not crash the program, suggesting that w contains the memory allocated by get_matrix and, hence, one does not need to allocate w in the main program.
At the same time, including allocate(w(2,2)) in the code suppresses the compiler warning. Despite having the impression that the same memory is allocated twice, valgrind does not report a memory leak and, in fact, reports exactly the same memory usage.
What is the correct way to store an allocatable array as result of a function?
Is it necessary to allocate w before storing in it the result of get_matrix?
No need to pre-allocate, or deallocate. The compiler will take care of this. The following code works as expected with Intel fortran.
program Console1
implicit none
! Variables
real(8), allocatable :: A(:,:)
integer :: i, j
! Body of Console1
A = get_matrix(6,4)
do i=1, size(A,1)
print '(*(g9.4),1x)', A(i,:)
end do
contains
function get_matrix(n,m) result(res)
integer, intent(in) :: n,m
real(8), allocatable :: res(:,:)
integer :: i
allocate(res(n,m))
res = 0d0
forall(i=1:min(n,m)) res(i,i)=1d0
end function
end program Console1
Output:
1.000 0.000 0.000 0.000
0.000 1.000 0.000 0.000
0.000 0.000 1.000 0.000
0.000 0.000 0.000 1.000
0.000 0.000 0.000 0.000
0.000 0.000 0.000 0.000
PS. Put functions inside the program declaration using a contains keyword. That way they are not external functions and no interface declaration is required.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With