【问题标题】:Variables being deleted in Fortran Arrays?Fortran 数组中被删除的变量?
【发布时间】:2018-06-08 08:42:31
【问题描述】:

我有以下代码,其中包含一个抽象类型、继承类型和一个简短的程序,我在其中创建一个对象并将其存储在一个数组中。

module m
    implicit none

    type :: container
        class(a), allocatable :: item
    end type container

    type, abstract :: a
        integer, public :: num
    end type a

    type, extends(a) :: b
        integer, public :: num2
   end type b
end module m

program mwe
    use m

    implicit none

    class(a), allocatable :: o1
    class(container), allocatable :: arr(:)

    o1 = b(1, 2)

    allocate(arr(2))
    arr(1) = container(o1)

    select type(t => o1)
        type is(b)
        write(*,*) t%num, t%num2
    end select

    select type(t => arr(1)%item)
        type is(b)
        write(*,*) t%num, t%num2
    end select
end program mwe

问题是,输出看起来像这样:

       1           2
       1           0

可以看出,存储在数组中的同一个变量使第二个变量无效。为什么会这样?是不是因为数组的类型是a,只包含第一个变量?

我正在用ifort version 18.0.3 编译代码。

【问题讨论】:

  • "arr(1)%item = o1" 适用于 gfortran-8.1, tio.run/… 但原始代码给出“错误:在 (1) 的内在赋值中不可分配的变量不能是多态的”
  • @roygvib,在该链接代码中,您重新排序了派生类型的定义(containera 之后)。那是因为 gfortran 8 还不支持问题中的顺序吗?
  • 是的,如果“容器”高于“a”(result with OP's order),gfortran 会给出以下错误(您可以在此处修改代码并按下上方的“运行(>)”按钮 :)
  • 有趣,谢谢@roygvib。我读过 gfortran 8 支持“递归可分配组件”(Fortran 2008 功能),所以令我惊讶的是它不接受原始订单。

标签: arrays fortran intel-fortran fortran2008


【解决方案1】:

我相信

arr(1) = container(o1)

Fortran 2008 无效。这是一个内在的赋值语句,但标准的第 7.2.1.2 节说

在内部赋值语句中,(1) 如果变量是多态的,它应该是可分配的,而不是 coarray。

据我所知,arr(1) 是多态的,但不可分配,因此符合标准的编译器应该发出错误并中止编译。

如果我的推理是正确的,英特尔 Fortran 编译器编译此代码的事实是编译器错误,应该向英特尔报告。

【讨论】:

  • 好点,但我不会称它为编译器错误。这是对程序而不是编译器的约束。 [QoI 问题,也许是因为缺少诊断。] 值得一提的是,我们看到的 arr 的代码没有理由是多态的(实际上,改变它并不能解决意外的输出)。跨度>
  • 我的理解是标准中的“shall”一词确立了处理器必须满足的要求......
  • 现在这是一个有趣问题的基础!该标准定义了 Fortran 程序的外观以及应该如何解释 Fortran 程序。总的来说,这些限制是针对程序的,但是在您看到诸如“C713”之类的东西的地方,这意味着编译器必须能够检测到违反程序规定的约束的情况。更广泛地说,一个 Fortran 处理器不是根据它如何处理非 Fortran 程序来判断的。有关详细信息,请参阅标准的概述部分。
【解决方案2】:

与ripero 的answer 一样,可以说程序的任何输出都是有效的。但是,我们可以对代码进行简单的修改以使其正确 Fortran。1此答案与此修改后的版本有关。

我会将此称为意外输出并寻求编译器供应商的帮助。

使用具有多态可分配组件的结构构造函数是 Fortran 中的新领域之一。编译器可能需要一段时间才能赶上或正确完成。

我已经使用 Intel Fortran 18.0.2 测试了您的代码并看到了相同的输出。

关于你的问题

是不是因为数组是a类型,只包含第一个变量?

否:在select type 部分中,输出为tb 类型的非多态实体。

您可以通过避免使用结构构造函数来解决这个问题:

arr(1)%item = o1

我还看到 18.0.2 之前的英特尔编译器仍然做一些不同的事情。


1 带声明

    class(container), allocatable :: arr(:)

arr 是多态和可分配的。正如ripero 所指出的,这意味着arr(1)arr 的元素是多态的。但是,作为数组元素,arr(1) 本身不是多态的,因此可能不在内部赋值语句的左侧。我们可以通过两种方式更改代码:提供定义的赋值,或者使arr 不是多态的。在问题的代码中似乎没有理由让容器多态,所以我会考虑

type(container), allocatable :: arr(:)

此外,正如 cmets 关于问题的讨论,如果您希望使用 gfortran 8 或更早版本来查看会发生什么,您还应该修改问题中的代码,以便派生类型的定义 container出现在派生类型 a 的定义之后。

【讨论】:

  • container 类型有一个标量组件item,该类型只有一个integer 组件。是不是期望container 类的对象arr(1) 只能存储一个integer,并且尝试打印第二个组件将给出任意值(可能是由于-限制内存访问)?
  • 组件item是多态的,声明类型a。在我们的示例中,它具有动态类型b,它确实有两个组件,因为这是分配给arr(1) 的结构构造函数中o1 的动态类型。任何打印声明类型为a 的对象的组件num2 的尝试都应被编译器检测为违规,并且不会被编译。但是,类型保护意味着 t 的声明类型为 b
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-09-03
  • 2022-06-10
  • 2016-08-02
  • 2022-10-05
  • 2017-10-19
  • 1970-01-01
  • 2013-11-29
相关资源
最近更新 更多