2015-04-21 14 views
6

Ich bin ein ziemlich Anfänger in OOP mit Fortran und ich versuche, ein Programm mit Prozeduren zu schreiben, die polymorphe Variablen als Argumente behandeln. Obwohl mein ursprünglicher Code viel komplizierter ist (viele Prozeduren, mehrere abgeleitete Typen usw.), könnte ich ein einfaches Beispiel meines Problems isolieren, sagen wir: Ich habe eine Prozedur, die eine polymorphe Variable kopiert und diese Kopie geringfügig modifiziert.Fortran-Polymorphie, Funktionen und Zuweisung

MODULE my_module 

type :: my_type 
    real :: data 
endtype my_type 

type, extends(my_type) :: my_derived_type 
end type my_derived_type 

CONTAINS 

subroutine sub_copy(old,new) 
implicit none 
class(my_type), intent(in) :: old 
class(my_type), allocatable, intent(out) :: new 
allocate(new, source = old) 
new%data = new%data + 1 
end subroutine sub_copy 

END MODULE my_module 

PROGRAM my_prog 
use my_module 
implicit none 
type(my_derived_type) :: x 
class(my_type), allocatable :: y 

x%data = 1.0 
call sub_copy(x,y) 
print*,y%data 
deallocate(y) 

END PROGRAM my_prog 

Dies führt schön sowohl in Bezug auf das erwartete Ergebnis und die Speicherzuweisung/Freigabe: Verwendung eines Subroutine

konnte ich erfolgreich mein Testprogramm schreiben.

Allerdings habe ich seit Tagen kämpfen, um zu versuchen, ein Fortran Funktion arbeiten, die die gleiche Arbeit machen würde.

Es scheint, dass eine Funktion in ähnlicher Weise an das Unterprogramm definiert (siehe hier nach) nicht einfach als

y = fun_copy(x) 

und meinem gfortran Compiler (v5.0.0) verwendet wird, klagt:

Error: Assignment to an allocatable polymorphic variable at (1) is not yet supported 

Ich habe hier und da gelesen, dass eine solche Zuordnung tatsächlich von meinem Compiler nicht unterstützt wird. Darauf wartend habe ich versucht, das zu umgehen, indem ich meinen eigenen Zuweisungsoperator (=) definiert habe. Der folgende Code funktioniert:

MODULE my_module 

type :: my_type 
    real :: data 
endtype my_type 

type, extends(my_type) :: my_derived_type 
end type my_derived_type 

interface assignment(=) 
    module procedure myassign 
end interface 

CONTAINS 

function fun_copy(old) result(new) 
implicit none 
class(my_type), intent(in) :: old 
class(my_type), allocatable :: new 
allocate(new, source = old) 
new%data = new%data + 1 
end function fun_copy 

subroutine myassign(new,old) 
class(my_type), intent(in) :: old 
class(my_type), allocatable, intent(out) :: new 
allocate(new, source=old) 
end subroutine 

END MODULE my_module 

PROGRAM my_prog 
use my_module 
implicit none 
type(my_derived_type) :: x 
class(my_type), allocatable :: y 

x%data = 1.0 
y = fun_copy(x) 
print*,y%data 
deallocate(y) 

END PROGRAM my_prog 

Es arbeitet in dem Sinne, dass in der Tat, eine Kopie von x als y erstellt. Das Speicherbudget dieses einfachen Testprogramms (ich benutze die Instrument Software auf OS X), aber es scheint, dass einige Speicher nicht vor dem Ende freigegeben wird. Ich vermute, dass die Kopie Funktion und die Zuweisung Unterprogramm sowohl Speicher zuweisen und dass ich nur ein Vorkommen frei, so dass eine zugewiesen.

Da ich beabsichtige, eine solche Routine eine große Anzahl von Malen in einem viel komplizierteren Code zu verwenden, bin ich wirklich besorgt über Speicherzuweisung/Freigabe. Natürlich kann ich die Unterroutine Version des Programms verwenden, aber wenn es einen Weg gibt, würde ich die Funktion Version bevorzugen.

Gibt es eine Möglichkeit, mit einem solchen Problem umzugehen?

+0

In Ihrem Funktionsbeispiel meinen Sie 'y = fun_copy (x)', denke ich. Als weitere Problemumgehung 'allocate (y, source = fun_copy (x))' ', aber das ist nicht so attraktiv. Es wäre interessant zu sehen, ob das Gleiche weiter besteht. – francescalus

+0

@francescalus Ja meinte ich 'y = fun_copy (x)'. Ich habe den ursprünglichen Beitrag bearbeitet und korrigiert. Außerdem habe ich gerade Ihre Problemumgehung versucht, und das Problem der Speicherzuweisung/-freigabe bleibt bestehen. Soweit ich das beurteilen kann, ändert sich nichts. – Reno

+0

Nun, ich kenne die Antwort (noch?) Nicht, aber ich nehme an, dass wir eine definierte Zuweisung als Problem ausschließen können. – francescalus

Antwort

0

Das klingt ähnlich wie eine Frage, die ich über Funktion vs Subroutinen eine Weile zurück hatte:

fortran operator overloading: function or subroutine

Ich denke, dass es eine Art Kompromiss ist ein Unterprogramm zwischen der Verwendung, die Zuweisung und Freigabe ermöglicht, und Verwenden einer Funktion, die nur zuordnen kann. Ich würde vorschlagen, dass, wenn die Datenstrukturen groß sind, Funktionen für diese Verwendung vermieden werden und sich an Subroutinen halten.

1

Haben Sie versucht, Zeiger zu verwenden?

module my_module 

     implicit none 

     type :: my_type 
      real :: data 
     contains 
      procedure    :: sub_copy 
      procedure    :: fun_copy_ptr 
      procedure    :: fun_copy_alloc 
      procedure, pass (this) :: my_assign 
      generic    :: assignment(=) => my_assign 
     end type my_type 

     type, extends(my_type) :: my_derived_type 
     end type my_derived_type 

    contains 

     subroutine sub_copy(this, new) 
      class(my_type), intent (in)    :: this 
      class(my_type), allocatable, intent (out) :: new 

      allocate(new, source=this) 
      new%data = new%data + 1 

     end subroutine sub_copy 

     function fun_copy_alloc(this) result (new) 
      class(my_type), intent(in) :: this 
      class(my_type), allocatable :: new 

      allocate(new, source=this) 
      new%data = new%data + 1.0 

     end function fun_copy_alloc 

     function fun_copy_ptr(this) result (new) 
      class(my_type), intent(in) :: this 
      class(my_type), pointer :: new 

      allocate(new, source=this) 
      new%data = new%data + 1.0 

     end function fun_copy_ptr 

     subroutine my_assign(new, this) 
      class(my_type), intent(in)    :: this 
      class(my_type), allocatable, intent(out) :: new 

      allocate(new, source=this) 

     end subroutine 

    end module my_module 

    program my_prog 

     use my_module, only: & 
      my_type, & 
      my_derived_type 

     implicit none 
     type(my_derived_type)  :: x 
     class(my_type), allocatable :: y 
     class(my_type), pointer  :: y_ptr => null() 

     x%data = 1.0 

     ! Case 1 
     call x%sub_copy(y) 
     print *, y%data 
     deallocate(y) 

     ! Case 2 
     y_ptr => x%fun_copy_ptr() 
     print *, y_ptr%data 
     deallocate(y_ptr) 

     ! Case 3 
     allocate(y, source=x%fun_copy_alloc()) 
     print *, y%data 
     deallocate(y) 

    end program my_prog