【问题标题】:Fortran: (mis)matching dynamic typesFortran:(错误)匹配动态类型
【发布时间】:2014-10-05 10:49:32
【问题描述】:

我正在将某个类的变量复制到同一类的另一个中。编译器很乐意编译它,但我担心在运行时动态类型可能会有所不同。我是否需要测试这两个对象是否具有相同的动态类型以防止在正方形中复制矩形,或者我可以信任编译器吗?如果一个矩形不小心复制到一个正方形中会怎样?

我想要做的是:

type :: simVars
        class(stateVars), dimension(:), allocatable :: svars
        integer                                     :: count_
    contains
        procedure :: init    => init_simVars
        procedure :: destroy => dest_simVars
        procedure :: add     => add_to_simVars              ! adds an observation to the time series
end type simVars

subroutine init_simVars(this,n)
!--> VERSION 1
    class(simVars), intent(inout) :: this
    integer,        intent(in)    :: n

    allocate( this%svars(n) )

    this%count_ = 0
end subroutine init_simVars

subroutine init_simVars(this,n,sVarsIni)
!--> VERSION 2
    class(simVars), intent(inout) :: this
    integer,        intent(in)    :: n
    class(stateVars), intent(in)  :: sVarsIni

    allocate( this%svars(n),source=sVarsIni )

    this%count_ = 0
end subroutine init_simVars

subroutine add_to_simvars(this,svars)
    class(simVars),   intent(inout) :: this
    class(stateVars), intent(in)    :: svars

    this%count_ = this%count_+1

    this%svars(this%count_) = svars
end subroutine add_to_simvars

subroutine doSimulation(simHist,sVarsIni)
    class(simVars),   intent(out) :: simHist
    class(stateVars), intent(in)  :: sVarsIni
         !--> dynamic type 'stateVars1'

    class(stateVars), allocatable :: sVars   ! will be source allocated from 'iniState'

    ! initialize the state of the economy
    allocate( sVars, source=sVarsIni )    ! "copies" 'sVarsIni' in 'sVars'

    ! initialize 'simHist'
    !--> VERSION 1:
    call simHist%init(nYears)
    !--> VERSION 2:
    call simHist%init(nYears,iniState)

    ! save today's variables
    call simHist%add(sVars)
    ...
end subroutine doSimulation

编译器 (ifort 14) 可以愉快地编译这两个版本,但我强烈怀疑 VERSION 1 是错误的。在init_simVars 中,this%svars 将分配给动态类型stateVars,在add_to_simvars 中,sVars 将具有动态类型stateVars1,并且将尝试在this%sVarsstateVars 类型)中进行复制。即使编译器无法确定add_to_simvarssVars 的动态类型,我也感到非常惊讶。运行时会发生什么,是段错误还是什么?

VERSION 2 我认为是正确的,但是我有点不愿意相信这里的编译器,因此我想我应该 ASSERT 认为 this%sVarssVars 具有相同的动态类型 (ASSERT(SAME_TYPE_AS(this%sVars, sVars) ))?这是一个真正的问题还是我太担心了?

另一个问题是当我执行allocate( this%svars(n),source=sVarsIni ) 时会发生什么。我想将数组this%sVars 分配为大小n 和动态类型sVarsIni。但是 sVarsIni 是一个标量。它会做我想做的事吗?

【问题讨论】:

    标签: fortran fortran2003


    【解决方案1】:

    区别就在这几行

    allocate( this%svars(n) )
    

    对比

    allocate( this%svars(n),source=sVarsIni )
    

    其中this%svarsclass(svars) 可分配数组,svarsIni 是class(stateVars) 虚拟参数。

    这确实改变了很多。

    在第一种情况下,它将它分配给声明的类型,即svars,在另一种情况下,它分配给虚拟参数的动态类型,至少为stateVars

    如果您使用版本 1,它应该会在 add_to_simvars 失败,因为动态类型将不匹配。

    我不知道你是否超载了那里的作业。如果你不这样做,它甚至不应该编译,因为多态对象的内在分配。

    【讨论】:

    • 你完全正确,我有点想你在说什么,但我忽略了我在父类stateVars 上重载了=。这意味着编译器总是知道如何处理this%svars(this%count_) = svars。总而言之,如果我没有弄乱赋值运算符,就不会编译 VERSION1。但是如果不重载=,VERSION2 也不会编译,对吗?因为编译器无法确定动态类型是否相同。 ...试过了,如果不重载=,它确实无法编译。
    • 是的,编译器的问题将出在add_to_simvars,因此在没有重载赋值的情况下,这两种情况下都会编译失败。版本 1 会在运行时出现问题。
    • 最后一条评论,我在扩展类上也重载了=。代码编译,我认为这是因为如果动态类型恰好不同,编译器将始终能够调用父类的= 重载例程。这是合法的,但会导致严重的运行时错误污染this%sVars,因此使用上述断言绝对有用。
    • 这很大程度上取决于派生类型中的实际内容,以及从程序逻辑的角度来看您可以允许或不能允许的内容。我可以想象很多情况,重载的= 足以让一切运行良好。在其他情况下,您确实需要动态类型相同。您可以使用select type 进行类似的检查,但在这种情况下,如果您将检查放入add_to_simvarssame_type_as() 可能会更好。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-09-12
    • 2015-05-05
    • 2013-01-16
    • 1970-01-01
    • 2014-02-05
    • 1970-01-01
    相关资源
    最近更新 更多