Reputation: 483
I have a derived type that contains a set allocatable arrays and I'm trying to overload some operators. As my arrays can become very large I don't want Fortran to do implicit copy of my arrays, but I can't figure out what is it actually done. Here is a minimal program that illustrate my point:
module type_vector_field
implicit none
type vector_field
double precision, dimension(:), allocatable :: f
end type vector_field
interface operator(+)
module procedure vector_field_add
end interface
contains
function vector_field_add(vf1, vf2) result(vf3)
type(vector_field), intent(in) :: vf1, vf2
type(vector_field) :: vf3
print*, "vf* addresses in add: ", loc(vf1), loc(vf2), loc(vf3)
vf3%f = vf1%f + vf2%f
end function vector_field_add
subroutine vector_field_add2(vf1, vf2, vf3)
type(vector_field), intent(in) :: vf1, vf2
type(vector_field), intent(out) :: vf3
print*, "vf* addresses in add2: ", loc(vf1), loc(vf2), loc(vf3)
vf3%f = vf1%f + vf2%f
end subroutine vector_field_add2
end module type_vector_field
The addition of two vector_field
can be done either by the +
operator or by the vector_field_add2
subroutine. I tested this with the following sample program:
program main
use type_vector_field
implicit none
integer :: n = 6283
type(vector_field) :: vf1, vf2, vf3
allocate(vf1%f(n), vf2%f(n))
vf1%f = 3.1415
vf2%f = 3.1415
!! first version
allocate(vf3%f(n))
print*, "vf* addresses in main: ", loc(vf1), loc(vf2), loc(vf3)
vf3 = vf1 + vf2
print*, "vf* addresses in main: ", loc(vf1), loc(vf2), loc(vf3)
print*, vf3%f(n)
deallocate(vf3%f)
!! second version
allocate(vf3%f(n))
print*, "vf* addresses in main: ", loc(vf1), loc(vf2), loc(vf3)
call vector_field_add2(vf1, vf2, vf3)
print*, "vf* addresses in main: ", loc(vf1), loc(vf2), loc(vf3)
print*, vf3%f(n)
end program main
And this is what it outputs when compiled with gfortran-4.8.2:
$ gfortran -g -Wall test.f90 -o test && test
vf* addresses in main: 6303968 6304032 6304096
vf* addresses in add: 6303968 6304032 140733663003232
vf* addresses in main: 6303968 6304032 6304096
6.2829999923706055
vf* addresses in main: 6303968 6304032 6304096
vf* addresses in add2: 6303968 6304032 6304096
vf* addresses in main: 6303968 6304032 6304096
6.2829999923706055
It seems that the subroutine works directly with the vf3
instance defined in the main scope, while the operator create an other vf3
instance in its scope and copy back the result. When I print the arrays addresses instead of the derived type addresses, I get:
vf*%f addresses in main: 39440240 39490512 39540784
vf*%f addresses in add: 39440240 39490512 0
vf*%f addresses in main: 39440240 39490512 39591056
6.2829999923706055
vf*%f addresses in main: 39440240 39490512 39540784
vf*%f addresses in add2: 39440240 39490512 0
vf*%f addresses in main: 39440240 39490512 39540784
6.2829999923706055
Hence the operator seems to copy the address of its vf3%f
in the vf3%f
instance of the main scope, while the subroutine works directly with the vf3%f
of the main scope. In both cases, I don't understand where points the vf3%f
of both the subroutine and the operator.
My questions:
+
operator, or should I drop this idea?Upvotes: 1
Views: 317
Reputation:
The problem you encounter has, as far as I can see, nothing to do with operator overloading.
More or less by accident (I presume) you had INTENT(OUT)
in your subroutine vector_field_add2, and you don't have it in vector_field_add.
One often-overlooked effect of INTENT(OUT)
is that all allocatable arrays get deallocated if the dummy arguments have the allocatable attribute upon entry into vector_field_add2. The same goes for types having components with the allocatable attribute.
If you have
real, dimension(:), allocatable: my_array
allocate(my_array(some:thing))
and then do
call sub1(my_array)
with
sub1(a)
real, dimension(:), intent(out) :: a
nothing surprising happens.
If you do instead
call sub2(a)
where sub2 is
subroutine sub2(a)
real, dimension(:), allocatable, intent(out) :: a
end subroutine sub2
the call to sub2 is equivalent to a call to deallocate
. If you leave out the intent(out)
or replace it, e.g. with intent(inout)
, nothing happens.
The same thing happened to you, only you had the allocatable component inside your type, so it was even less visible.
Otherwise, there is no difference if you use an operator or if you call a subroutine directly. It only matters for clarity of the code. The compiler translates the assignment statement with the overloaded operator to the subroutine call.
If you want to see how it is done, translate your program using the -fdump-tree-original
option. This will generate a file with the main name like your source file, with an added .003.original, where you can see a C-like representation of your Fortran code.
Upvotes: 1