Fortran:复制新目标时自动将指针重新分配给新目标

Fortran:复制新目标时自动将指针重新分配给新目标,fortran,Fortran,这是我最近几天遇到的问题的一个例子。假设您具有以下结构: TYPE superImportant INTEGER(C_INT) :: one END TYPE superImportant TYPE lessImportant TYPE(superImportant), POINTER :: ptr END TYPE lessImportant TYPE(superImportant), DIMENSION(:), ALLOCATABLE, TARGET :: superS

这是我最近几天遇到的问题的一个例子。假设您具有以下结构:

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
在代码中的某个点上,
superStruct
lesserStruct
被分配给大小
superSize
lesserSize
,对于
lesserStruct
的每个元素,执行类似的操作:

lesserStruct(lesserNumber)%ptr => superStruct(superNumber)
然后,在代码中再进一步,我需要将
superStruct
lesserctruct
重新分配到更大的大小。因此,我做了以下工作:

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)
这就像一个符咒:所有指针都被正确复制,我可以访问
1:lesserSize
中所有元素的
lesserStruct(.)%ptr
。 但是,如果我尝试对其他结构执行相同操作:

ALLOCATE(tempSuperStruct(superSize + newSuperSize))
tempSuperStruct(1:superSize) = superStruct(1:superSize)
CALL MOVE_ALLOC(tempSuperStruct, superStruct)
然后我无法再访问
lesserStruct(.%ptr
。我确定这是因为
=
的行。请注意,如果我这样做:

CALL MOVE_ALLOC(superStruct,tempSuperStruct)
我仍然可以访问
lesserStruct(.)%ptr
,因为,正如标准中所说:
如果to具有TARGET属性,则调用MOVE\u ALLOC时与from关联的任何指针都会相应地与to关联。
不幸的是,在此之后我仍然必须执行
=
步骤,在此期间,我失去了指针关联

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


提前谢谢

我认为你误解了MOVE\u ALLOC的用法

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

在第二步中,当您使用临时可分配和MOVE_ALLOC重新分配上层结构时,您正在更改上层结构存储其值的内存位置

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

CALL MOVE_ALLOC(superStruct,tempSuperStruct)
您所做的是将分配从“上层建筑”传递到“临时上层建筑”。现在,superStruct被释放,tempSuperStruct现在持有分配的空间。但如果你仔细观察它,你会发现它只有“superSize”元素,而没有“superSize+newSuperSize”。lesseStruct仍然有效(至少对于superSize元素),因为指向where is点的内存空间仍然以相同的方式使用

因此,您误解该标准的原因是,如果与FROM关联的指针具有TARGET属性,那么它将与TO关联。在您的情况下,与“tempSuperStructure”相关联的任何指针都将在MOVE_ALLOC之后与上层结构相关联,而不是lesserStruct中的指针

看到了吗


在您的情况下,我看到的唯一方法是在重新分配lesserStruct之后,将指针重新分配给上层结构的元素。

否-您需要重新考虑您的方法

如果指针总是与特定数组中的元素相关联(这里似乎就是这种情况),那么您可以只存储感兴趣的元素的索引。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)