Pointers Ifort:move_alloc()在指针的属性上,intent(in)触发错误

Pointers Ifort:move_alloc()在指针的属性上,intent(in)触发错误,pointers,memory-management,compiler-errors,fortran,Pointers,Memory Management,Compiler Errors,Fortran,我想扩展结构的可分配属性,这似乎是最干净的方法。因此,我使用指向结构作为参数的指针Intent(in)创建了一个例程,并尝试调用: Type(STRUCT1), Pointer, Intent(in) :: str1 ... call MOVE_ALLOC(TO= str1%arrayofint , FROM= temparray) 其中,str1是指向结构的指针,ArrayFint是要扩展的属性。请参阅以下示例代码的子程序LOC_extendsecond()编译器ifort返回以下错误:

我想扩展结构的可分配属性,这似乎是最干净的方法。因此,我使用指向结构作为参数的
指针Intent(in)
创建了一个例程,并尝试调用:

Type(STRUCT1), Pointer, Intent(in)  :: str1
...
call MOVE_ALLOC(TO= str1%arrayofint , FROM= temparray)
其中,
str1
是指向结构的指针,
ArrayFint
是要扩展的属性。请参阅以下示例代码的子程序
LOC_extendsecond()
编译器ifort返回以下错误:

Source1.f90(91): error #7999: The FROM or TO arguments of a MOVE_ALLOC reference must not be INTENT(IN).   [MOVE_ALLOC]
就好像str1%arrayFint是
Intent(in)
请记住,指针
str1
Intent(in)
,指针结构
str1%arrayFint
的属性是否被视为
Intent(in)

为了调查该问题,我尝试不使用
MOVE_AllOC()
,并发现在例程中取消分配或分配
str1%arrayFint
,不会触发ifort的任何错误或警告。请参阅示例代码的子例程
LOC_extendedfirst()

我的一位同事建议了一种解决方法(谢谢Luc!):创建指针的本地副本,并且可以使用指针的本地副本调用
MOVE\u AllOC()
,而不会引发错误。请参阅示例代码的子例程
LOC\u extendedthird()

Type(STRUCT1), Pointer, Intent(in)  :: str1
Type(STRUCT1), Pointer  :: str2
str2=>str1
...
call MOVE_ALLOC(TO= str2%arrayofint , FROM= temparray)
下面是示例代码:

Module Source1

    Implicit None

    Public :: STRUCT1

  Private

  Type STRUCT1
      Integer, dimension(:), allocatable    :: arrayofint 

  End Type STRUCT1

    Contains

    Subroutine newstruct1(str1,ier,errmsg)

        Type(STRUCT1), Pointer, Intent(inout)  :: str1
        Integer, Intent(out) :: ier
        character(len=256), Intent(out) :: errmsg

        ier=0
        allocate(str1,stat=ier, errmsg=errmsg)
        if( ier>0) return

        allocate(str1%arrayofint(2),stat=ier, errmsg=errmsg)
        if( ier>0) return

    End Subroutine newstruct1

    Subroutine LOC_extendfirst(str1,targetsize,ier,errmsg)
        Type(STRUCT1), Pointer, Intent(in)  :: str1
        Integer, Intent(out)  :: ier
        character(len=256), Intent(out)  :: errmsg
        Integer, Intent(in)  :: targetsize 

        Integer,dimension(1) :: shp
        Integer :: newsize , formersize
        Integer, dimension(:), allocatable :: temparray

        ier=0

        shp=shape(str1%arrayofint)
        formersize=shp(1)
        if (targetsize .GT. formersize) then
            newsize=MAX(targetsize,2*formersize)
            allocate(temparray(newsize),stat=ier, errmsg=errmsg)
            if( ier>0) then; return ; endif
            temparray(1:formersize)=str1%arrayofint
            allocate(temparray(formersize),stat=ier, errmsg=errmsg)
            if( ier>0) then; return ; endif 
            temparray=str1%arrayofint
            if(allocated(str1%arrayofint)) deallocate(str1%arrayofint)
            allocate(str1%arrayofint(newsize),stat=ier, errmsg=errmsg)
            if( ier>0) then; return ; endif  
            str1%arrayofint(1:formersize)=temparray
            if(allocated(temparray)) deallocate(temparray)
        endif

  End Subroutine LOC_extendfirst

      Subroutine LOC_extendsecond(str1,targetsize,ier,errmsg)
          Type(STRUCT1), Pointer, Intent(in)  :: str1
          Integer, Intent(out)  :: ier
          character(len=256), Intent(out)  :: errmsg
          Integer, Intent(in)  :: targetsize 

          Integer,dimension(1) :: shp
          Integer :: newsize , formersize
          Integer, dimension(:), allocatable :: temparray

          ier=0

          shp=shape(str1%arrayofint)
          formersize=shp(1)
          if (targetsize .GT. formersize) then 
               newsize=MAX(targetsize,2*formersize)
               allocate(temparray(newsize),stat=ier, errmsg=errmsg)
               if( ier>0) then; return ; endif
               temparray(1:formersize)=str1%arrayofint
               ! TODO uncomment the following line to get error from ifort
               call MOVE_ALLOC(TO= str1%arrayofint , FROM= temparray)
          endif

  End Subroutine LOC_extendsecond

  Subroutine LOC_extendthird(str1,targetsize,ier,errmsg)
      Type(STRUCT1), Pointer, Intent(in)  :: str1
      Integer, Intent(out)  :: ier
      character(len=256), Intent(out)  :: errmsg
      Integer, Intent(in)  :: targetsize 

      Integer,dimension(1) :: shp
      Integer :: newsize , formersize
      Integer, dimension(:), allocatable :: temparray

      Type(STRUCT1), Pointer  :: str2
      ier=0

      str2=>str1
      shp=shape(str2%arrayofint)
      formersize=shp(1)
      if (targetsize .GT. formersize) then 
          newsize=MAX(targetsize,2*formersize)
          allocate(temparray(newsize),stat=ier, errmsg=errmsg)
          if( ier>0) then; return ; endif
          temparray(1:formersize)=str1%arrayofint
          call MOVE_ALLOC(TO= str2%arrayofint , FROM= temparray)

      endif

  End Subroutine LOC_extendthird

  End Module Source1
在windows上调用ifort 19.0.2.190 IA32,使用
ifort/nologo/debug:full/Od/debug参数:all/warn:unused/warn:truncated\u source/warn:uncalled/warn:interfaces/Qsave/traceback/check:pointer/check:bounds/check:uninit/libs:static/threads/dbglibs/c/Qm32“Source1.f90”
会产生错误

相反,使用
gfortran-c Source1.f90-Wall在Debian上使用gcc 6.3.0中的gfortran不会导致任何错误:它只显示未使用函数的警告

关于Fortran,我是个新手。我知道Fortran指针封装的数据比C指针多得多,所以我想知道修改属性
str1%arrayFint
是否正确,因为
str1
指针,Intent(in)
,就像在函数中修改str1->arrayFint是正确的,因为指针str1是通过值传递的


如何解决ifort和gfortran之间的行为差异?ifort报告当前情况下的错误是否正确?为什么ifort认为str1%arrayFint是
Intent(in)
,好像str1
类型(STRUCT1)、Intent(in)
而不是
类型(STRUCT1)、指针、Intent(in)
?如
LOC\u extendthird()
中所示引入指针的本地副本是否是缓解该问题的最合适方法?

对于指针伪参数,
intent(in)
属性意味着指针不应出现在所谓的指针关联上下文中。不严格地说,这意味着不允许(潜在地)更改伪参数的指针关联。允许您更改此指针目标的值


对于指针伪参数,
intent(in)
属性不会“级联”到参数的子对象(例如在本例中的组件
arrayofint
):str1目标的组件
arrayofint
没有
intent(in)
属性

在类似于带有指针的
str1%arrayFint
的引用中,这是对
str1
目标的组件
arrayFint
的引用。即使
intent(in)
属性确实应用于指针伪参数的子对象,
str1%arrayofint
引用的对象也不是
str1
的子对象

ifort认为这样的对象具有
intent(in)
属性是错误的。您已经找到了一种有效的方法来解决ifort中的这些缺点。你应该考虑把这个缺陷报告给英特尔。< /P>

最后,也许有更好的方法来解决你的问题,在不使用指针哑参数的情况下调整组件的大小,但是我不会考虑这个答案。

对代码的无关紧要的评论:返回;endif可以替换为
if(ier>0)return
,即您可以使用一行
if
语句,而不使用
then
end if
。使用
intent(in)
属性,您可以“承诺”只使用数据,而不更改它-请参阅。将其更改为
intent(inout)
(默认的intent属性)应该可以解决此问题。感谢@HighPerformanceMark的反馈。在原始代码中,如果出现错误,则在返回之前调用其他例程。谢谢@jcerar:事实上,修改为Intent(inout)可以解决问题,但该例程在其他例程中调用,因此其他例程将被修改为Intent(inout),从而使代码越来越不可读。此外,据我所知,我履行了我的承诺:我不会在重新分配pointed结构的属性时更改指针
str1
。鉴于我在Fortran指针方面的经验有限,上一句可能最终被证明是错误的…@jcerar,使用
intent(in)
伪参数,您并没有承诺不更改数据:您只是承诺不更改指针关联。感谢@francescalus的回答。我真的需要一个有经验的fortran开发人员的观点,因为我的fortran实践并没有让质疑编译器的正确性看起来是明智的。根据您的建议,我将此问题发布在上。请随时向我们通报英特尔的任何结论。是的,当然!到目前为止,史蒂夫·莱昂内尔的观点与你的一致:ifort存在问题。他引用fortran标准(8.5.10p6):
如果非指针对象有意图