Fortran 数组中的变量被删除?
Variables being deleted in Fortran Arrays?
我有以下代码,其中包含一个抽象类型、继承类型和一个简短的程序,我在其中创建一个对象并将其存储在一个数组中。
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
编译代码。
与 ripero 的 一样,可以说程序的任何输出都是有效的。但是,我们可以对代码进行简单的修改,使其正确的Fortran。1这个答案是关于这个修改版本的。
我会称之为意外输出并寻求编译器供应商的帮助。
使用具有多态可分配组件的结构构造函数是 Fortran 中的新领域之一。编译器可能需要一段时间才能赶上或正确完成。
我已经使用 Intel Fortran 18.0.2 测试了您的代码并看到了相同的输出。
针对您的问题
Is it because the array is of type a
, which only contains the first variable?
否:在 select type
部分,输出 t
是类型 b
.
的非多态实体
您可以通过避免使用结构构造函数来解决此问题:
arr(1)%item = o1
我还看到 18.0.2 之前的英特尔编译器做了一些不同的事情。
1 随声明
class(container), allocatable :: arr(:)
arr
是多态的和可分配的。正如 ripero 所指出的,这意味着 arr(1)
,arr
的元素是多态的。但是,作为数组元素,arr(1)
本身不是多态的,因此可能不会位于内部赋值语句的左侧。我们可以通过两种方式更改代码:提供定义的赋值,或者使 arr
不是多态的。在问题的代码中似乎没有理由让容器多态,所以我会考虑
type(container), allocatable :: arr(:)
此外,正如问题评论中所讨论的,如果您希望使用 gfortran 8 或更早版本,看看会发生什么,您还应该修改问题中的代码,以便派生类型的定义 container
出现在派生类型 a
.
的定义之后
我相信
arr(1) = container(o1)
在 Fortran 2008 中是无效的。这是一个内部赋值语句,但是标准的第 7.2.1.2 节说
In an intrinsic assignment statement, (1) if the variable is polymorphic it shall be allocatable and not a coarray.
据我所知,arr(1)
是多态的但不可分配,因此符合标准的编译器应该发出错误并中止编译。
如果我的推理是正确的,英特尔 Fortran 编译器编译此代码的事实是一个编译器错误,应该报告给英特尔。
我有以下代码,其中包含一个抽象类型、继承类型和一个简短的程序,我在其中创建一个对象并将其存储在一个数组中。
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
编译代码。
与 ripero 的
我会称之为意外输出并寻求编译器供应商的帮助。
使用具有多态可分配组件的结构构造函数是 Fortran 中的新领域之一。编译器可能需要一段时间才能赶上或正确完成。
我已经使用 Intel Fortran 18.0.2 测试了您的代码并看到了相同的输出。
针对您的问题
Is it because the array is of type
a
, which only contains the first variable?
否:在 select type
部分,输出 t
是类型 b
.
您可以通过避免使用结构构造函数来解决此问题:
arr(1)%item = o1
我还看到 18.0.2 之前的英特尔编译器做了一些不同的事情。
1 随声明
class(container), allocatable :: arr(:)
arr
是多态的和可分配的。正如 ripero 所指出的,这意味着 arr(1)
,arr
的元素是多态的。但是,作为数组元素,arr(1)
本身不是多态的,因此可能不会位于内部赋值语句的左侧。我们可以通过两种方式更改代码:提供定义的赋值,或者使 arr
不是多态的。在问题的代码中似乎没有理由让容器多态,所以我会考虑
type(container), allocatable :: arr(:)
此外,正如问题评论中所讨论的,如果您希望使用 gfortran 8 或更早版本,看看会发生什么,您还应该修改问题中的代码,以便派生类型的定义 container
出现在派生类型 a
.
我相信
arr(1) = container(o1)
在 Fortran 2008 中是无效的。这是一个内部赋值语句,但是标准的第 7.2.1.2 节说
In an intrinsic assignment statement, (1) if the variable is polymorphic it shall be allocatable and not a coarray.
据我所知,arr(1)
是多态的但不可分配,因此符合标准的编译器应该发出错误并中止编译。
如果我的推理是正确的,英特尔 Fortran 编译器编译此代码的事实是一个编译器错误,应该报告给英特尔。