在 Fortran 重载赋值中检查自赋值 [英] checking for self-assignment in fortran overloaded assignment

查看:25
本文介绍了在 Fortran 重载赋值中检查自赋值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 fortran 2003 实现一个多项式类,其中包含重载的算术运算和赋值.派生类型维护术语定义和系数的可分配列表,如下所示

I am trying to implement a polynomial class with fortran 2003, with overloaded arithmetic operations and assignments. The derived type maintains allocatable list of term definitions and coefficients, like this

type polynomial
  private
    type(monomial),dimension(:),allocatable     ::  term
    double precision,dimension(:),allocatable   ::  coef
    integer                                     ::  nterms=0
  contains
   ...
end type polynomial

interface assignment(=)
   module procedure :: polynomial_assignment
end interface
   ...
contains
    elemental subroutine polyn_assignment(lhs,rhs)
      implicit none
      type(polynomial),intent(???)  :: lhs
      type(polynomial),intent(in)   :: rhs
 ...

我必须使它基本化,因为它旨在用作多项式矩阵.至少在大多数情况下,这确实有效.然而,我不知何故让自己担心这里的自我分配.可以简单地检查指针以查看 C++ 中的内容是否相同,但它似乎不是 Fortran 中的一个选项.但是编译器确实检测到自赋值并给了我一个警告.(gfortran 4.9.0)

I had to make it elemental because this is intended to be used as matrices of polynomials. That does work, for the most cases at least. However, I somehow got myself into concerns about self-assignment here. One can simply check the pointers to see if things are the same in C++, but it doesn't seem to be an option in Fortran. However the compiler do detect the self-assignment and gave me a warning. (gfortran 4.9.0)

当我有 lhs 的 intent(out) 时,lhs 和 rhs 的可分配条目似乎在进入子例程时被释放,这是有道理的,因为它们都是 p 和一个意图(out) 参数将首先被敲定.

When I have intent(out) for lhs, the allocatable entries for both lhs and rhs appeared to be deallocated on entry to the subroutine, which made sense since they were both p, and an intent(out) argument would first be finalized.

然后我尝试通过意图(inout)避免释放,并通过修改 lhs 输出中的一个字段来检查自分配

Then I tried to avoid the deallocation with an intent(inout), and check self-assignment by modifying one field in the lhs output

   elemental subroutine polyn_assignment(lhs,rhs)
      implicit none
      type(polynomial),intent(inout)  :: lhs
      type(polynomial),intent(in)   :: rhs
      lhs%nterms=rhs%nterms-5
      if(lhs%nterms==rhs%nterms)then
        lhs%nterms=rhs%nterms+5
        return
      end if
      lhs%nterms=rhs%nterms

好吧,现在这让我感到惊讶.当我这样做

Well, now this is what surprised me. When i do

p=p

它没有通过测试并继续进行,给了我一个多项式为 0 但没有内存冲突.一头雾水,我在赋值里面打印了lhs%nterms和rhs%nterms,才发现它们不一样!

It didn't make the test and proceeded, giving me a polynomial with 0 terms but no memory violations. Confused, I printed lhs%nterms and rhs%nterms inside the assignment, only to find that they are different!

更令人困惑的是,当我用

What is even more confusing is that when I did the same thing with

call polyn_assignment(p,p)

它完美运行并检测到两个参数相同.我很困惑子程序的接口如何与子程序本身不同地运行.

It works perfectly and detected that both arguments are the same. I am puzzled how an interface of a subroutine can run differently from the subroutine itself.

Fortran 2003 中的赋值有什么特别的地方我错过了吗?

Is there something special about assignment in Fortran 2003 that I've missed?

(第一次在这里提问.如果我没有做对,请纠正我.)

(First time to ask a question here. Please correct me if i didn't do it right.)

推荐答案

如果您有一个语句 a = b 通过子例程 sub 调用定义的赋值,则赋值语句等价于call sub(a, (b)).请注意括号 - 右侧的参数是计算括号表达式的结果,因此在概念上与 b 不是同一对象.详见 F2008 12.4.3.4.3.

If you have a statement a = b that invokes defined assignment via a subroutine sub, the assignment statement is equivalent to call sub(a, (b)). Note the parentheses - the right hand side argument is the result of evaluating a parenthesised expression and is therefore not conceptually the same object as b. See F2008 12.4.3.4.3 for details.

因此,a = a 等价于 call sub(a, (a)).这两个参数没有别名.它与call sub(a,a)不同,后者可能(取决于sub的内部细节,包括虚拟参数属性)破坏Fortran的参数别名规则(例如,在您的示例中,诸如 call polyn_subroutine(a,a) 之类的语句是非法的).

Consequently, a = a is equivalent to call sub(a, (a)). The two arguments are not aliased. It is different from call sub(a,a), the latter may (depending on the specifics of the internals of sub, including dummy argument attributes) break Fortran's argument aliasing rules (e.g. in your example, a statement such as call polyn_subroutine(a,a) is illegal).

这篇关于在 Fortran 重载赋值中检查自赋值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆