2009-12-09 8 views
14

alcune domande su record in Delphi:Records a Delfi

  1. Come record sono quasi come le classi, perché non utilizzare solo le classi al posto di record?
  2. In teoria, la memoria viene allocata per un record quando viene dichiarata da una variabile; ma, e come viene rilasciata la memoria dopo?
  3. Posso capire l'utilità dei puntatori ai record in un oggetto elenco, ma con Contenitori generici (TList<T>), è necessario utilizzare il puntatore? se no, come eliminare/rilasciare ogni record in un contenitore generico? Se voglio cancellare un record specifico in un contenitore generico, come farlo?

risposta

10

Per 1 e 2: i record sono tipi di valori, mentre le classi sono tipi di riferimento. Vengono allocati nello stack o direttamente nello spazio di memoria di qualsiasi variabile più grande che li contenga, anziché tramite un puntatore e automaticamente ripuliti dal compilatore quando escono dall'ambito.

Come per la terza domanda, uno TList<TMyRecord> dichiara internamente uno array of TMyRecord per lo spazio di archiviazione. Tutti i record in esso saranno ripuliti quando l'elenco viene distrutto. Se si desidera eliminare uno specifico, utilizzare il metodo Delete da eliminare per indice o il metodo Remove per trovare ed eliminare. Ma sappi che dal momento che è un tipo di valore, tutto ciò che fai sarà fare copie del record, non copiare riferimenti ad esso.

+0

Grazie Mr. Wheeler e una domanda in più: Puntatore per registrare = Classe? –

+1

No, puntatore a record = puntatore a record. Un oggetto (istanza di classe) è diverso da un record in diversi modi. –

3

Ci sono alcune altre differenze tra una classe e un record. Le classi possono utilizzare polymorphism ed esporre le interfacce. I record non possono implementare i distruttori (sebbene da Delphi 2006 possano ora implementare costruttori e metodi).

I record sono molto utili per segmentare la memoria in una struttura più logica poiché il primo elemento di dati nel record si trova allo stesso punto di indirizzo del puntatore al record stesso. Questo non è il caso per le classi.

+0

Inoltre, i record supportano l'overloading dell'operatore, che può essere utile in alcune situazioni. –

19

Ci sono molte differenze tra record e classi; e no "Puntatore da registrare" <> "Classe". Ognuno ha i suoi pro e contro; una delle cose importanti sullo sviluppo del software è di comprenderle in modo da poter scegliere più facilmente la più appropriata per una determinata situazione.

  1. Questa domanda è basata su una premessa sbagliata. I record non sono come le classi, nello stesso modo in cui gli interi non sono quasi come i doppi.
    • Le classi devono sempre essere istanziate dinamicamente, mentre questa è una possibilità, ma non un requisito per i record.
    • Le istanze di classi (che chiamiamo oggetti) vengono sempre passate per riferimento, il che significa che più sezioni di codice condivideranno e agiranno sulla stessa istanza. Questo è qualcosa di importante da ricordare, perché potresti involontariamente modificare un oggetto come un effetto collaterale; anche se quando fatto intenzionalmente è una caratteristica potente. I record d'altra parte sono passati per valore; devi indicare esplicitamente se li stai passando per riferimento.
    • Le classi non "copiano facilmente come record". Quando dico copia, intendo un'istanza separata che duplica una fonte. (Questo dovrebbe essere ovvio alla luce del valore/commento di riferimento sopra).
    • I record tendono a funzionare molto bene con i file digitati (perché sono così facili da copiare).
    • I record possono sovrapporre campi con altri campi (caso x di/unioni)
    • Questi erano commenti su certi vantaggi situazionali dei record; al contrario, ci sono anche vantaggi situazionali per le classi che non approfondirò.
  2. Forse il modo più semplice per capirlo è essere un po 'pedanti. Chiariamo; la memoria non è realmente allocata 'quando è dichiarata', è allocata quando la variabile è in scope e deallocata quando esce dalla portata. Quindi, per una variabile locale, viene allocata poco prima dell'inizio della routine e rilasciata subito dopo la fine. Per un campo classe, viene assegnato quando viene creato l'oggetto e deallocato quando viene distrutto.
  3. Anche in questo caso, ci sono pro e contro ...
    • Può essere più lenta e richiedono più memoria per copiare interi dischi (come con i generici) che a basta copiare i riferimenti.
    • Il passaggio dei record in base al riferimento (utilizzando i puntatori) è una tecnica potente che consente di modificare facilmente la propria copia del record. Senza questo, dovresti passare il tuo record in base al valore (cioè copiarlo), riceverai il record modificato di conseguenza, copialo di nuovo nelle tue strutture.
  4. I puntatori ai record come le classi? No, per niente. Solo due delle differenze:
    • Le classi supportano l'ereditarietà polimorfica.
    • Le classi possono implementare interfacce.
+0

Grazie Marco per aver aggiunto la nota sui record delle varianti (usando il caso x di ...) –

9

Uno dei principali vantaggi di record è, quando si dispone di una grande "serie di record". Questo viene creato in memoria allocando spazio per tutti i record in uno spazio RAM contiguo, che è estremamente veloce. Se avessi usato "array of TClass", ogni oggetto nella matrice avrebbe dovuto essere allocato da solo, il che è lento.

C'è stato molto lavoro per migliorare la velocità di allocazione della memoria, al fine di migliorare la velocità di stringhe e oggetti, ma non sarà mai così veloce come la sostituzione di 100.000 allocazioni di memoria con 1 allocazione di memoria.

Tuttavia, se si utilizza un array di record, non copiare il record in variabili locali. Questo può facilmente uccidere il beneficio della velocità.

3

1) Per consentire l'ereditarietà e il polimorfismo, le classi hanno un sovraccarico. I record non li consentono e in alcune situazioni potrebbe essere un po 'più veloce e semplice da usare. A differenza delle classi, che vengono sempre allocate nell'heap e gestite tramite riferimenti, i record possono essere allocati nello stack anche, acceduti direttamente e assegnati tra loro senza richiedere di chiamare un metodo "Assegna". Anche i record sono utili per accedere ai blocchi di memoria con una determinata struttura, poiché il loro layout di memoria è esattamente come lo definisci. Un layout di memoria di istanza di classe è controllato dal compilatore e ha ulteriori dati per far funzionare gli oggetti (cioè il puntatore alla Tabella dei metodi virtuale).

2) A meno che non si assegnino i record dinamicamente, utilizzando New() o GetMem(), la memoria del record viene gestita dal compilatore come ordinali, float o array statici: la memoria delle variabili globali viene allocata all'avvio e rilasciata al termine del programma, e le variabili locali sono allocate nello stack entrando in una funzione/procedura/metodo e rilasciate in uscita. L'allocazione/rilascio della memoria nello stack è più veloce perché non richiede chiamate al gestore di memoria, sono solo poche le istruzioni dell'assemblatore per modificare i registri dello stack.Ma sappi che allocare una grande struttura nello stack può causare un overflow dello stack, perché la dimensione massima dello stack è fissa e non molto grande (vedi le opzioni del linker). Se i record sono campi di una classe, vengono assegnati quando la classe viene creata e rilasciata quando la classe viene liberata.

3) Uno dei vantaggi dei generici è quello di eliminare la necessità della gestione puntatore di basso livello, ma essere consapevoli del funzionamento interno.

Problemi correlati