【发布时间】:2015-02-26 13:53:39
【问题描述】:
我有一个包含一组可分配数组的派生类型,我正在尝试重载一些运算符。由于我的数组可能变得非常大,我不希望 Fortran 对我的数组进行隐式复制,但我无法弄清楚它实际上做了什么。这是一个说明我的观点的最小程序:
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
两个vector_field 的加法可以通过+ 运算符或vector_field_add2 子例程来完成。我使用以下示例程序对此进行了测试:
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
这是使用 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
似乎子例程直接与主范围中定义的vf3 实例一起工作,而操作员在其范围内创建另一个vf3 实例并复制回结果。当我打印数组地址而不是派生类型地址时,我得到:
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
因此,运算符似乎将其vf3%f 的地址复制到主作用域的vf3%f 实例中,而子例程直接与主作用域的vf3%f 一起工作。在这两种情况下,我都不明白子例程和运算符的vf3%f 指向哪里。
我的问题:
- 有没有办法确定运算符和子程序在哪个数组中写入结果?
- 有没有办法在使用
+运算符时避免复制,还是我应该放弃这个想法?
【问题讨论】:
-
在
vf3=vf1+vf3的情况下您希望会发生什么? -
我没有想到这个案例。我希望
vf1的值被添加到vf3中,这从vue 的内存地址点来看是一团糟,我的子程序vector_field_add2崩溃了。 无效的内存引用您是否建议我因为您的情况而在不创建临时数组的情况下无法实现+? -
就是这样。特别是,对于
c=a+b,结果a+b被完全评估,并将结果分配给c。我不会写完整的答案,因为它可能包含在我对stackoverflow.com/q/28241473/3157076 的回答中。 [虽然我不会称之为重复。]
标签: fortran operator-overloading fortran90 dynamic-arrays