2013-05-08 21 views
6

Attualmente sto provando a codificare una piccola subroutine in Fortran per deallocare tutte le variabili allocate in memoria quando il mio programma arriva a un errore, cioè un file non caricato o un file necessario inesistente. A questo punto, l'esecuzione deve essere terminata, ma non tutti gli allocataboli sono necessariamente allocati (dipende da dove è apparso sul codice l'errore è apparso), quindi non posso fare una pulizia deallocandoli tutti.Fortran DEALLOCATE

Il mio approccio attuale è la seguente:

SUBROUTINE Cleanup(A) 

    REAL(8), ALLOCATABLE, DIMENSION(:) :: A 

    IF (ALLOCATED(A)) THEN 
     DEALLOCATE(A) 
    END IF 

END SUBROUTINE 

e chiamare "pulizia" per ogni allocatable. Il problema con questo è che non tutte le mie variabili sono dimensione-1. Ho un massimo di tre dimensioni in alcuni di essi.

Prima ho pensato di scrivere 3 diverse subroutine per diverse dimensioni e l'utilizzo di overload, ma questo non sembra essere molto elegante.

Poi mi è venuto in mente che forse potevo passare un puntatore anziché l'argomento actuall A, ma ho cercato su Google e sembra che non sia possibile deallocare una variabile di destinazione tramite un puntatore.

Qualche idea su come farlo correttamente?

Grazie.

+4

Quando l'esecuzione viene interrotta, tutte le risorse utilizzate dal codice vengono automaticamente liberate in qualsiasi modo, quindi non devi preoccuparti di rilasciarle esplicitamente. –

+1

So che Fortran libera automaticamente la memoria, ma in questo caso sto scrivendo una DLL che viene chiamata da Labview, quindi questo è chi gestisce la memoria. Quando la DLL giunge a un errore, Labview si interrompe improvvisamente e, se provo a rieseguire, mostrerà il messaggio: "La matrice è già allocata" e si spegne. Ciò significa che la memoria non viene deallocata correttamente. – derkomai

+1

Nota: 'reale (8)' non è garantito che sia 8 byte. Un modo portabile è 'usa ISO_FORTRAN_ENV',' real (real64) 'per 64 bit. –

risposta

7

Il mio approccio a questo sarebbe utilizzare una combinazione dei seguenti elementi:

  • A partire dal Fortran 95, tutte le variabili locali allocatable non salvati che vengono assegnati quando una procedura finiture sono deallocate automaticamente. Se questo è applicabile dipende da come viene chiamata la tua DLL, e quindi se puoi effettivamente strutturare cose tali che tutti i tuoi allocatables sono locali non salvati.

  • Al Fortran 2003 (o Fortran 95 + TR allocatable - questo livello linguaggio è ampiamente supportata tra Fortran mantenuti) argomenti effettivi definibili passati a INTENT (OUT) argomenti fittizi definibili verranno deallocato automaticamente prima dell'avvio della procedura di esecuzione . La tua routine di pulizia nella domanda deve solo aggiungere la dichiarazione dell'argomento fittizio come INTENT (OUT) e quindi non è necessario il test IF o DEALLOCATE. Devi comunque scrivere la routine per ciascun tipo e classifica che devi pulire.

  • Analogamente al precedente, i componenti allocabili delle variabili di tipo derivate passate a un argomento fittizio INTENT (OUT) verranno automaticamente deallocati. Quindi potresti essere in grado di raccogliere tutte le variabili allocabili insieme come componenti in un oggetto di tipo derivato. La pulizia implica semplicemente il passaggio dell'oggetto a una procedura con un dummy INTENT (OUT). INTENT (OUT) qui ripristina anche i componenti che hanno l'inizializzazione predefinita di nuovo al loro valore "predefinito". Forse c'è anche un'altra pulizia che devi fare manualmente a questo punto (file chiusi, ecc.).

  • Un approccio alternativo, sempre utilizzando i tipi derivati ​​con tutte le variabili come componenti, consiste nel rendere allocabile l'oggetto tipo derivato stesso. Quando hai bisogno di ripulire, basta deallocare quell'unico oggetto: i suoi componenti saranno automaticamente deallocati. Fortran 2003 consente di attivare una procedura finale da questo tipo di eventi se si dispone di ulteriori operazioni di pulizia da eseguire a questo punto.

Un approccio tipo derivato rende anche facile avere più istanze di qualsiasi DLL supporta autonomamente attiva ad una volta (basta più oggetti di tipo derivato).

Esempi dell'approccio tipo derivato, trovati:

TYPE MyType 
    REAL, ALLOCATABLE :: variable_one(:) 
    INTEGER, ALLOCATABLE :: variable_two(:) 
    ... 
END TYPE MyType 

INTENT (OUT) fittizi

TYPE(MyType) :: object 
ALLOCATE(object%variable_one(xxx)) 
ALLOCATE(object%variable_two(yyy)) 
... 
IF (things_have_gone_wrong) CALL Cleanup(object) 
... 
SUBROUTINE Cleanup(arg) 
    TYPE(MyType), INTENT(OUT) :: arg 
END SUBROUTINE Cleanup 

oggetto ALLOCATABLE.

TYPE(MyType), ALLOCATABLE :: object 
ALLOCATE(object) 
ALLOCATE(object%variable_one(...)) 
ALLOCATE(object%variable_two(...)) 

... 
IF (things_have_gone_wrong) DEALLOCATE(object) 
+1

Che funziona benissimo, grazie mille! – derkomai

+2

Un altro modo che ho trovato per risolvere questo problema è l'utilizzo di macro del preprocessore: #define Cleanup (A) SE (assegnato (A)) DEALLOCATE (A) Quando ha chiamato, Cleanup fa il lavoro. – derkomai