问题
I have a type var that contains a pointer p. I need to copy var on another variable var1 of the same type as var (by doing var1 "=" var, in quotation because I do not know if it is the correct way, see below).
In my implementation var and var1 are passed to a subroutine that needs to initialise var1 to var and then modify var1. If I change the values of var1%p, then var%p is modified as well. So, I need to change the values of the memory zone pointed by var1%p, without modifying the memory zone pointed by var%p. What is the correct way to do that in Fortran (2003, Intel) ?
Code example:
type variable
real, dimension(:), pointer:: p
end type variable
subroutine init(var,var1) !This of course will not work
type (variable):: var, var1
var1=var
end subroutine
Now, I need to be able to do something equivalent to changing var1%p without affecting var%p. I cannot change variable (I am modifying existing code).
Following solution below (if I am correct): I declare var1 as:
Type(variable), allocatable:: Var1
then allocate and initialize:
allocate(var1, source=var)
var1 = var
Then
call somesub(var1)
that modifies var1%p, has the consequence to modify var%p such that var%p is equal to var1%p.
Edit 3: Doing:
subroutine init(var,var1)
type(variable), intent(in):: var
type(variable), allocatable, intent(inout):: var1
allocate(var1%p, source=var%p)
var1%p = 2
end subroutine init
type variable:: var
type variable, allocatable:: var1
call init(var, var1)
The above compiles but crashes (hangs infinitely). Using instead:
allocate(var1, source=var)
runs but updates var%p to 1.
回答1:
When you do an intrinsic assignment of derived type variables, any pointers are copied using pointer assignment => (which just copies the address and other properties of the existing piece of memory). You must make sure a new target is allocated in memory and the value of the array is copied there.
You can create your own overloaded assignment for the given type and than use the syntax var1 = var1, or you can code the proper assignment into your subroutine, if it suffices:
subroutine init(var,var1) !This of course will not work
type(variable) :: var, var1 !DO NOT FORGET THIS WHEN POSTING EXAMPLES NEXT TIME!
allocate( var1%p(lbound(var%p,1):ubound(var%p,1)) )
var1%p = var%p
end subroutine
As HighPerformance Mark commented, if you do not have other reasons to use pointers, allocatable components are MUCH better.
type variable
real, dimension(:), allocatable :: p
end type variable
subroutine init(var,var1) !This WILL work
type (variable):: var, var1
var1 = var
end subroutine
In your edit you have the same problem:
var1 = var
That is exactly the same problem as before, you didn't change anything!
Also
allocate(var1, source=var)
should have the same effect as the original code, I believe you need
allocate(var1%p, source=var%p)
but I already commented that most common versions of gfortran will not accept that and will require the shape to be specified explicitly.
The variables var and var1 do not have to be allocatable. But they can be, if it is required for some other reason.
It is possible to write the user defined assignment once and then overload the intrinsic assignment (=).
type variable
real :: pointer :: p(:)
contains
procedure :: assign
generic :: assignment(=) => assign
end type
subroutine assign(out, in)
class(variable), intent(out) :: out
class(variable), intent(in) :: in
allocate( out%p(lbound(in%p,1):ubound(in%p,1)) )
out%p = in%p
end subroutine
Then you can write var1 = var whenever you want and it will call the subroutine assign automatically.
来源:https://stackoverflow.com/questions/34854078/fortran-copy-of-pointer