Fortran copy of pointer

╄→гoц情女王★ 提交于 2020-01-02 08:34:19

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!