2013-02-19 22 views
14

Nella mia applicazione ho il seguente record:Devo finalizzare l'array di record in Delphi?

TTransaction = record 
    Alias: string 
    Description: string 
    Creation: TDateTime 
    Count: Integer 
end; 

e sto usando questo record in questo array:

Transactions = array of TTransaction; 

Sto mantenendo la matrice caricata durante la fase di esecuzione, ma ad una data tempo ho bisogno di cancellare tutti i dati e aggiungere alcuni nuovi.

E 'quanto basta per usare:

SetLength(Transactions, 0); ? 

o devo finalizzare qualcosa?

risposta

15

Ci sono tre modi per rilasciare gli associati di memoria con un array dinamico, a:

SetLength(a, 0); 
Finalize(a); 
a := nil; 

Sta a te scegliere quale utilizzare.

Il documentation dice lo stesso, anche se in un leggermente intorno modo:

deallocare una matrice dinamica, assegnare zero a una variabile che fa riferimento alla matrice o passare la variabile per finalizzare; uno di questi metodi dispone dell'array, purché non ci siano altri riferimenti ad esso. Gli array dinamici vengono rilasciati automaticamente quando il loro conteggio dei riferimenti scende a zero.Gli array dinamici di lunghezza 0 hanno il valore nullo.

In questo modo verrà rilasciata tutta la memoria associata all'array, inclusi tutti i tipi gestiti nidificati, come stringhe, arrys dinamici ecc. Che appartengono al tipo di record.

Se è necessario ridimensionare l'array per un utilizzo futuro e disporre dei nuovi dati disponibili, è sufficiente ridimensionare utilizzando SetLength e inizializzare gli elementi rimanenti in modo appropriato.

+1

Does 'Finalize' in realtà cambia il valore di' a', però? Ho sempre avuto l'impressione che non lo facesse - che libera la memoria lasciando l'indirizzo originale dell'array dinamico memorizzato in 'a', in previsione di una successiva chiamata a' Free' o 'Initialize'. –

+1

@Rob Per una matrice dinamica, queste tre opzioni sono tutte equivalenti. Per un tipo gestito, Finalize deve impostare il riferimento su zero. Non ha scelta. Si consideri una variabile locale di tipo array dinamico. –

+0

@DavidHeffernan Nei casi in cui il limite massimo dell'array è 10, è meglio usare: 1- Impostare su Nil e ricreare tutto. 2 - Associare gli indici utilizzati ai valori successivi ?? – EProgrammerNotFound

0

SetLength (transactions,0) non è una buona idea. Penso che il modo migliore sia reinizializzare tutti i membri del record. In questo modo, mantieni la variabile caricata.

È possibile utilizzare SetLength (transactions,0) se non si ha più bisogno della variabile, per utilizzare la minor quantità di memoria possibile. Naturalmente, se ne hai ancora bisogno da qualche parte nel programma, puoi regolarne la lunghezza, supponendo che tu lo sappia.

Non è necessario finalizzare nulla, perché è un record, non una classe. I record non hanno costruttori o distruttori, classi simili.

+0

* "puoi regolarne la lunghezza" * - ma ricorda che probabilmente otterrai tutti i vecchi elementi copiati con tutti i loro contenuti statici ei contenuti dinamici (stringhe, array din) probabilmente avranno il loro conteggio ref aumento/diminuzione. È per questo che uso la deallocazione full array prima di cambiare la lunghezza in alcuni casi. * "Non è necessario finalizzare nulla, perché è un record, non una classe" * - è vero solo se tutti i campi del record sono tipi semplici (non stringhe/din array/interfacce). – Fr0sT

10

L'impostazione della lunghezza dell'array su zero distruggerà l'array, il che contrasta con il desiderio di "mantenere l'array caricato". Tuttavia, lo libererà la memoria per tutti i record e le loro stringhe (per le stringhe il cui numero di riferimento è 1 alla volta).

Se si desidera solo liberare la memoria per le stringhe, ma mantenere la memoria del record allocata (perché si pianifica di allocare un altro set di record subito dopo, e non si desidera lo spreco di rilascio e riallocazione del stessa memoria), quindi è possibile cancellare solo i membri della stringa, ma non c'è una singola chiamata di libreria per farlo per voi. Invece, dovrai scrivere un ciclo e cancellare autonomamente i campi di ogni record.

for i := 0 to High(transactions) do begin 
    transactions[i].alias := ''; 
    transactions[i].description := ''; 
end; 

Se ci sono molti campi del record che necessitano di compensazione, allora potrebbe essere più conveniente per assegnare un valore predefinito TTransaction ad ogni elemento della matrice. È possibile utilizzare la funzione Default, o nelle vecchie versioni di Delphi è possibile dichiarare una TTransaction che ha tutti i suoi campi chiaro già:

const 
    ClearTransaction: TTransaction = (alias: ''; description: ''; creation: 0; count: 0); 

for i := 0 to High(transactions) do 
    transactions[i] := ClearTransaction; 
    // or 
    transactions[i] := Default(TTransaction); 
+0

Penso che questo sia il migliore da fare ... dato che è l'utente che decide quando vuole caricare tutti i dati, sapevo che i tipi di record sono una struttura e nel mio caso di tipi primitivi, questo è il motivo per cui ho chiesto. grazie per la risposta – EProgrammerNotFound

+0

La domanda esistente che tocca l'argomento trattato nella seconda parte della risposta è: http://stackoverflow.com/questions/11065821/how-to-properly-free-records-that-taintain- vari-types-in-delphi-at-once –

+0

@DavidHeffernan ho letto questo argomento ed è per questo che ho chiesto informazioni sulla finalizzazione. Mi sono confuso con così tante risposte, e quel tizio che parlava di finalize + fillchar ... – EProgrammerNotFound