【问题标题】:Assign pointer in derived type to target in the same type in Fortran在 Fortran 中将派生类型的指针分配给相同类型的目标
【发布时间】:2021-05-10 16:47:40
【问题描述】:

我想在派生类型中分配一个指针,该派生类型包含在同一派生类型中。下面的代码给了我下面的错误。这是怎么回事,我该如何解决?

   24 |         zoos(i)%tigers(1) => zoos(i)%animals(1, 1)
      |        1
Error: Expected bounds specification for 'zoos' at (1)
module mo_zoo
    implicit none
    type zoo
        integer, dimension(:,:), pointer :: animals
        integer, dimension(:), pointer :: tigers
        integer, dimension(:), pointer :: ducks
    end type zoo
   
    save
        type(zoo), dimension(:), pointer :: zoos
end module mo_zoo

program test
    use mo_zoo
    implicit none
    integer :: n_zoos
    integer :: i

    n_zoos = 4
    allocate(zoos(n_zoos))

    do i = 1, n_zoos
        allocate(zoos(i)%animals(10, 2))
        zoos(i)%tigers(1) => zoos(i)%animals(1, 1)
        zoos(i)%ducks(1) => zoos(i)%animals(1, 2)
    end do
end program test

【问题讨论】:

  • 我认为我的情况更复杂,因为指针包含在派生类型的数组中。
  • fortran 中指针的第一条规则:不要使用指针。 Allocatables 几乎总是优越的 - 当然二维数组没有理由在这里显示不可分配,可能与 target 属性取决于你做什么
  • 但是我很难理解你的数组的维度。为什么动物是二维数组,而老虎和鸭子是一维数组?当你做指针赋值时,你只指向一个元素,那为什么是一维数组呢?
  • 我想指向数组中的一个范围。对不起,我的 Fortran 生锈了,这是我很久以来的第一次编码。

标签: fortran


【解决方案1】:

问题与派生类型无关,报错信息错误。

问题是zoos(i)%ducks是一个指向数组的指针,而不是一个指针数组,所以你需要将zoos(i)%ducks指向zoos(i)%animals(:, 2),而不是zoos(i)%ducks(1)指向zoos(i)%animals(1, 2)

这个in this answer之前已经谈过了。

我相信这可以满足您的需求:

module mo_zoo
    implicit none
    type zoo
        integer, dimension(:,:), pointer :: animals
        integer, dimension(:), pointer :: tigers
        integer, dimension(:), pointer :: ducks
    end type zoo
   
    save
        type(zoo), dimension(:), pointer :: zoos
end module mo_zoo

program test
    use mo_zoo
    implicit none
    integer :: n_zoos
    integer :: i

    n_zoos = 4
    allocate(zoos(n_zoos))

    do i = 1, n_zoos
        allocate(zoos(i)%animals(10, 2))
        zoos(i)%tigers => zoos(i)%animals(:, 1)
        zoos(i)%ducks => zoos(i)%animals(:, 2)
    end do
end program test

我还想提供一个框架挑战。正如 cmets 所指出的,尤其是 Ian Bush 所指出的,Fortran 中的指针是出了名的容易出错。

我建议用allocatables 替换任何分配的pointers。如果pointers 指向它们,这些allocatables 也必须是targets,如下所示:

module mo_zoo
    implicit none
    type zoo
        integer, dimension(:,:), allocatable :: animals
        integer, dimension(:), pointer :: tigers
        integer, dimension(:), pointer :: ducks
    end type zoo
   
    save
        type(zoo), dimension(:), allocatable, target :: zoos
end module mo_zoo

program test
    use mo_zoo
    implicit none
    integer :: n_zoos
    integer :: i

    n_zoos = 4
    allocate(zoos(n_zoos))

    do i = 1, n_zoos
        allocate(zoos(i)%animals(10, 2))
        zoos(i)%tigers => zoos(i)%animals(:, 1)
        zoos(i)%ducks => zoos(i)%animals(:, 2)
    end do
end program test

在可能的情况下,使用allocatables 比使用pointers 有很多优势:

  • allocatables 占用的内存将在allocatables 退出范围时自动释放1
  • 编译器可以对allocatables 做出比pointers 更强的假设,有时会导致代码更快。

1 至少,根据 Fortran 标准,这是正确的。一些编译器(尤其是this bug)存在几个与最终确定相关的突出问题。

【讨论】:

  • 确实有效。我认为指向第一个元素会起作用,但我显然在考虑 C 风格。
  • @veryreverie 我也一直在使用 Gfortran 作为我的主编译器(谢谢!!),我的经验是 allocatable 派生类型中的数组现在非常成熟/稳定,我基本上没有遇到最近的问题(例如,即使对于具有嵌套可分配对象的“深拷贝”对象)。但我仍然避免使用 (1) final 例程(以及对象的意图(out)),以及 (2) 多态分配 + LHS 的自动分配(相反,我使用像 allocate(objA, source=objB) 这样的源分配)。考虑到这两个警告,我认为allocatable 只是“可以”使用(或推荐),尤其是 gfort >= 10 :)
  • (FWIW,没有声称答案,但我对可分配组件感到有点过度担心(?)...)如果可能,将结果与至少两个编译器(ifort 和 gfort)进行比较) 可能有用的建议(虽然我总是忘记这样做...XD)
  • 我在 gfortran 中广泛使用 inten( out ) 和多态赋值 + LHS 的自动分配,并且最近没有遇到任何问题(gfortran 7+)。不过,我不使用定稿(很多)——它是那些对我来说总是很有趣的功能之一,但在检查时并不完全符合我的需求。
  • @roygvib 我不断遇到的是this bug 的变体。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-09
  • 2017-08-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多