Make pointers (alias) to alloacatable arrays elements in user defined type

Make pointers (alias) to alloacatable arrays elements in user defined type

I use ifort 12.0.4 , for compilation and run I type following line:

ifort PointerBugSol.f90

a.out

Becouse in my calculation I use very complicated formulas, and data types, for me is extremly important to have ability to alias allocatable arrays elements. For me is alsow very important to use allocatable arrays - not other constructions. Below you have 2 codes. First one use trick and work, second don't use trick and doesn't work.

program PointerBugSol

type :: StatisticOutMeridItem_type
 character :: name*(32) 
 real, allocatable :: m(:,:)
 end type
 type :: Statistics_type 
 real :: avgValM
 type(StatisticOutMeridItem_type), allocatable :: collectStatisticsMeridItems(:) ! (CSMI)
 end type

type(Statistics_type) statistics
 type(StatisticOutMeridItem_type), pointer :: p 
 integer :: i,j,k

!---------- Initialize
allocate(statistics%collectStatisticsMeridItems(3))
 do k=1,3
 allocate(statistics%collectStatisticsMeridItems(k)%m(10,10))
 statistics%collectStatisticsMeridItems(k)%m=k+1
 print *,"values on init:",statistics%collectStatisticsMeridItems(k)%m(1,1),k
 statistics%collectStatisticsMeridItems(k)%name="test"
 end do
!------------- Run test
call ptrGet(statistics%collectStatisticsMeridItems(1),p) ! now p is alias to st%collectStatisticsMeridItems(1)
p%m=(p%m+1)*p%m + (p%m*2.1)**(p%m-1) - 3./p%m + p%m**2

call ptrGet(statistics%collectStatisticsMeridItems(2),p) ! now p is alias to st%collectStatisticsMeridItems(2)
 p%m=(p%m+1.5)*p%m + (p%m*3.1)**(p%m-1) - 4./p%m + p%m + (p%m+31)*p%m + (p%m*2.1)**(p%m-2)
!------------- Veiw results
print *,"After test:"
 do k=1,3
 print *,"values on stop:",statistics%collectStatisticsMeridItems(k)%m(1,1),k
 end do

contains

subroutine ptrGet(el,r)
 type(StatisticOutMeridItem_type), target :: el
 type(StatisticOutMeridItem_type), pointer :: r
 r => el
 end subroutine

end program

Second code:

program PointerBugSol

type :: StatisticOutMeridItem_type
 character :: name*(32) 
 real, allocatable :: m(:,:)
 end type
type :: Statistics_type 
 real :: avgValM
 type(StatisticOutMeridItem_type), allocatable, target :: collectStatisticsMeridItems(:) ! (CSMI)
 end type

type(Statistics_type) statistics
 type(StatisticOutMeridItem_type), pointer :: p 
 integer :: i,j,k

!---------- Initialize
allocate(statistics%collectStatisticsMeridItems(3))
 do k=1,3
 allocate(statistics%collectStatisticsMeridItems(k)%m(10,10))
 statistics%collectStatisticsMeridItems(k)%m=k+1
 print *,"values on init:",statistics%collectStatisticsMeridItems(k)%m(1,1),k
 statistics%collectStatisticsMeridItems(k)%name="test"
 end do
!------------- Run test
p=>statistics%collectStatisticsMeridItems(1) 
 p%m=(p%m+1)*p%m + (p%m*2.1)**(p%m-1) - 3./p%m + p%m**2
p=>statistics%collectStatisticsMeridItems(2) 
 p%m=(p%m+1.5)*p%m + (p%m*3.1)**(p%m-1) - 4./p%m + p%m + (p%m+31)*p%m + (p%m*2.1)**(p%m-2)
!------- Show results
 print *,"After test:"
 do k=1,3
 print *,"values on stop:",statistics%collectStatisticsMeridItems(k)%m(1,1),k
 end do

end program

Here is compilation message fo recond code:

PointerBug1.f90(32): error #6796: The variable must have the TARGET attribute or be a subobject of an object with the TARGET attribute, or it must have the POINTER attribute. [STATISTICS]
p=>statistics%collectStatisticsMeridItems(2)


The differences is that in line 09 in second code attrib "target" appear, and in first code we use tricky function "ptrGet" (ilnes 25 and 28). In second code we use direct way to get pointer (lines 25 and 27)

Why first code works, but second code don't ? There exist non-tricky , direct way, to get pointer to allocatable array element in user define type?

4 posts / novo 0
Último post
Para obter mais informações sobre otimizações de compiladores, consulte Aviso sobre otimizações.

My post, has some errors and chaos. Now I edit it. Please look on it now.

Pointers can only be pointed at things that have the target attribute (hence the error message from your second code). To get the target attribute a thing either explicitly has to have have TARGET in its declaration, or be a POINTER. This is so the compiler knows which things might be aliased (can be referenced by multiple names) and can adjust its optimisations to suit.

In your initial subroutine workaround, you give the dummy argument the TARGET attribute, hence you can point something at it. BUT, there's a significant problem with this approach. Because the actual argument being passed into ptrGet does not have the target attribute, the pointer association status of p is undefined when the ptrGet subroutine returns. It may appear as if things are working, but formally your program is in error. Chances are one day a change in compiler implementation (particularly around compiler optimisations) may break your program.

Your colleague's suggestion directly adds the TARGET attribute to the thing be pointed at - problem solved.

But -- use of pointers (and target) is a great way to inhibit compiler optimisations. Fortran 2003 introduces the ASSOCIATE construct that can help in this situation. Before F2003 there's also the option of putting the complicated expression in its own little function.


associate(p => statistics%collectStatisticsMeridItems(2))

  p%m=(p%m+1)*p%m + (p%m*2.1)**(p%m-1) - 3./p%m + p%m**2

end associate

Steve

Faça login para deixar um comentário.