繁体   English   中英

指向 arrays 的指针作为 Fortran 派生类型中的成员变量

[英]Pointers to arrays as member variables in Fortran derived type

Fortran 无法将派生类型的成员变量作为目标。 (我想这与未指定派生类型如何存储在 memory 中的标准有关?)但是,我可以将指针作为成员变量并将指针与指针相关联。 就像我在下面的例子中所做的那样。

module DataMod

   type DataType

      real(8), private, dimension(:,:), pointer, contiguous :: A
      real(8), private, dimension(:,:), pointer, contiguous :: B

      integer :: n

   contains 

      procedure :: alloc
      procedure :: set
      procedure :: print_
      final :: dealloc

   end type DataType

   interface DataType
      procedure :: NewDataType
   end interface DataType

   contains

   function NewDataType(dimension_) result(new)

      integer, intent(in) :: dimension_

      type(DataType) :: new

      new%n = dimension_

   end function NewDataType

   subroutine alloc(dataObject)

      class(DataType) :: dataObject

      allocate(dataObject%A(dataObject%n,dataObject%n))
      allocate(dataObject%B(dataObject%n,dataObject%n))

   end subroutine alloc

   subroutine set(dataObject, datas, choice)

      class(DataType) :: dataObject

      real(8), dimension(dataObject%n,dataObject%n), intent(in) :: datas

      character(len=1), intent(in) :: choice

      real(8), dimension(:,:), pointer :: dataPointer
      integer :: i,j

      if(choice .eq. 'A') then
         datapointer => dataObject%A
      elseif(choice .eq. 'B') then
         datapointer => dataObject%B
      else
         stop
      endif

      do j = 1,dataObject%n
         do i = 1,dataObject%n
            datapointer(i,j) = datas(i,j)
         enddo
      enddo

   end subroutine set

   subroutine print_(dataObject)

      class(DataType), intent(in) :: dataObject

      print *, 'A'
      print *, dataObject%A(1:dataObject%n,1:dataObject%n)
      print * 
      print *, 'B'
      print *, dataObject%B(1:dataObject%n,1:dataObject%n)

   end subroutine print_

   subroutine dealloc(dataObject)

      type(DataType) :: dataObject

      deallocate(dataObject%A)
      deallocate(dataObject%B)

   end subroutine dealloc

end module DataMod


program DataTest

   use DataMod, only: DataType

   implicit none

   real(8), dimension(2,2) :: testArray
   type(DataType) :: testType

   testType = DataType(2)
   call testType%alloc()

   testArray(1,1) = 1
   testArray(2,1) = 2
   testArray(1,2) = 3
   testArray(2,2) = 4

   call testType%set(testArray, 'A')

   testArray(1,1) = 5
   testArray(2,1) = 6
   testArray(1,2) = 7
   testArray(2,2) = 8

   call testType%set(testArray, 'B')

   call testType%print_()

end program DataTest

在 set 例程中,我使用一个 if 语句来设置一个指针,以决定它是否应该将传入的矩阵转储到 A 或 B 中。在我目前正在处理的程序中,我必须决定将四个不同矩阵的哪个组合相乘并且设置一对指针比编写 16 个几乎相同的 dgemm 调用要好得多。

我的问题是,除了悬挂指针等的正常危险之外,这种方法是否还有任何问题,或者没有指针就可以做到这一点? 不应从 object 外部访问 arrays。是否存在任何性能问题?

类型定义中的组件可能不使用 TARGET 属性声明(除了缺少语法,这将与当前语言中的其他概念和规则不一致),但如果派生类型的变量具有 TARGET 属性,则其所有子对象也有 TARGET 属性。 对于类型定义:

type DataType
  real(8), private, dimension(:,:), allocatable :: A
  real(8), private, dimension(:,:), allocatable :: B
  ...

程序集可以写成...

 subroutine set(dataObject, datas, choice)
   class(DataType), TARGET :: dataObject
   real(8), dimension(dataObject%n,dataObject%n), intent(in) :: datas
   character(len=1), intent(in) :: choice
   real(8), dimension(:,:), pointer :: dataPointer

   ! require dataobject%A and ..%B to already be allocated.
   if(choice .eq. 'A') then
     datapointer => dataObject%A
   elseif(choice .eq. 'B') then
     datapointer => dataObject%B
   else
     stop
   endif

   datapointer = datas    ! or some other operation.
   ...

dataPointer可以声明为连续的,它指向的可分配 arrays 始终是连续的。)

没有 TARGET 属性的实际参数可能与具有 TARGET 属性的伪参数相关联。 如果是这种情况,则与伪参数关联的指针在过程执行完成时变为未定义。 (在某些情况下,此类指针也可能变得未定义,即使实际参数具有 TARGET 属性 - 有关详细信息,请参阅 F2018 15.5.2.4p8 - 但这些情况不适用于标量。)

因此,在一般情况下,如果指向派生类型 object 的组件之一的指针需要比上面set的过程更长寿(例如,如果dataPointer不是set的本地对象)并且您不能确保实际参数将始终具有 TARGET 属性,那么使用指针组件的原始方法可能更合适。 问题中的实现似乎没问题——尽管我建议使终结器 IMPURE ELEMENTAL 使事情对未来的变化更加稳健。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM