Fortran:在复制时自动重新指定指向新目标的指针

时间:2016-05-11 17:58:35

标签: fortran

以下是我过去几天遇到的问题。假设您有以下结构:

TYPE superImportant
    INTEGER(C_INT) :: one
END TYPE superImportant

TYPE lessImportant
    TYPE(superImportant), POINTER :: ptr 
END TYPE lessImportant

TYPE(superImportant), DIMENSION(:), ALLOCATABLE, TARGET :: superStruct
TYPE(lessImportant),  DIMENSION(:), ALLOCATABLE         :: lesserStruct

在代码中的某个时刻,superStructlesserStruct分配给尺寸superSizelesserSize,并且对于lesserStruct的每个元素,这样做了:

lesserStruct(lesserNumber)%ptr => superStruct(superNumber)

然后,在代码中稍微进一步,我需要将superStructlesserStruct重新分配给更大的尺寸。所以我做了以下几点:

TYPE(superImportant), DIMENSION(:), ALLOCATABLE, TARGET :: tempSuperStruct
TYPE(lessImportant),  DIMENSION(:), ALLOCATABLE         :: tempLesserStruct

ALLOCATE(tempLesserStruct(lesserSize + newLesserSize))
tempLesserStruct(1:lesserSize) = lesserStruct(1:lesserSize)
CALL MOVE_ALLOC(tempLesserStruct, lesserStruct)

就像一个魅力:所有指针都被正确复制,我可以访问lesserStruct(.)%ptr中所有元素的1:lesserSize。 但是,如果我尝试对其他结构做同样的事情:

ALLOCATE(tempSuperStruct(superSize + newSuperSize))
tempSuperStruct(1:superSize) = superStruct(1:superSize)
CALL MOVE_ALLOC(tempSuperStruct, superStruct)

然后我再也无法访问lesserStruct(.)%ptr了。我发现这是因为=的行。请注意,如果我改为:

CALL MOVE_ALLOC(superStruct,tempSuperStruct)

我仍然可以访问lesserStruct(.)%ptr,因为正如标准中所述:If to has the TARGET attribute, any pointer associated with from at the time of the call to MOVE_ALLOC becomes correspondingly associated with to.不幸的是,我之后仍然需要执行=步骤,在此期间我失去指针关联

所以这是我的问题:有没有办法以“MOVE_ALLOC方式”复制我的结构,所以与它相关的指针会自动跟随?更一般地说,是否有更好的解决方案来扩展我的结构的大小?

提前致谢!

2 个答案:

答案 0 :(得分:2)

我认为你误解了MOVE_ALLOC的使用。

当您使用临时allocatable和MOVE_ALLOC重新分配lesserStruct时,事实上,您正在保留指针,这就是为什么您仍然可以在此步骤之后使用它们。

在第二步中,当您使用临时allocatable和MOVE_ALLOC重新分配superStruct时,您正在改变superStruct存储其值的内存位置。

在步骤2中,当你简单地做一个

CALL MOVE_ALLOC(superStruct,tempSuperStruct)

你正在做的是传递" superStruct"到" tempSuperStruct"。现在,superStruct被释放,tempSuperStruct现在保存已分配的空间。但是如果你看一下,你会发现它只有超级大小的'元素,而不是superSize + newSuperSize'。 lesseStruct仍然有效(至少对于superSize元素),因为到达where的内存空间仍然以相同的方式使用。

因此,您误解标准的原因是,如果具有TARGET属性,则与FROM关联的任何指针都将与TO关联。在您的情况下,任何指针与" tempSuperStructure"那就是你的FROM将在MOVE_ALLOC之后与superStructure相关联,而不是来自lesserStruct的指针......

请参阅?

在你的情况下,我看到的唯一方法是在重新分配lesserStruct之后重新分配指向superStruct元素的指针。

答案 1 :(得分:1)

不 - 您需要重新考虑您的方法。

如果指针始终与特定数组中的元素相关联(这似乎就是这种情况),那么您只需存储感兴趣元素的索引即可。 Fortran对数组和数组索引操作有很好的支持,所以你也可以利用这种支持。

另一种方法是将目标数组的各个元素保存为持久标量对象,当展开目标数组时,这些对象实际上不会被移动,而不是被分配。

TYPE superImportant
  INTEGER(C_INT) :: one
END TYPE superImportant

TYPE superImportantWrapper
  ! Using a pointer to reference the object, because 
  ! it ensures the target is a TARGET, and simplifies 
  ! assignment.  ALLOCATABLE is also a possibility, 
  ! with other changes.
  TYPE(superImportant), POINTER :: item => NULL()
CONTAINS
  ! Elided code to deallocate the item component.
  FINAL :: wrapper_Final
END TYPE supertImportantWrapper

TYPE lessImportant
  TYPE(superImportant), POINTER :: ptr 
END TYPE lessImportant

! The super array is of the wrapper type.
TYPE(superImportantWrapper), DIMENSION(:), ALLOCATABLE, TARGET   &
    :: superStruct
TYPE(lessImportant),  DIMENSION(:), ALLOCATABLE :: lesserStruct

! Elided code to populate each scalar component of the wrapper type.
DO i = 1, xxx ; ALLOCATE(superStruct(i)%item) ; ... ; END DO

! Point at the component, not the wrapper object.
lesserStruct(lesserNumber)%ptr => superStruct(superNumber)%item

...

! Time to grow?  Again, array operations on the wrapper.
TYPE(superImportantWrapper), DIMENSION(:), ALLOCATABLE, TARGET :: tempSuperStruct

ALLOCATE(tempSuperStruct(superSize + newSuperSize))
! Intrinsic assignment of the pointer component means it maintains 
! the reference to the same object that lesser struct is referencing.
tempSuperStruct(1:superSize) = superStruct(1:superSize)
CALL MOVE_ALLOC(tempSuperStruct, superStruct)