2011-11-07 13 views
8

Ho sempre avuto l'impressione che gli oggetti in Delphi siano in realtà riferimenti a posizioni di memoria, che a loro volta ho immaginato fossero memorizzate come variabili puntatore.Perché TValue.Make richiede un puntatore a un riferimento a un oggetto?

Ora, voglio creare un TValue da un oggetto. Considera questo:

TValue.Make(AObject, TypeInfo(TMyObject), val); 

dove val: TValue. Questo non funzionerà. Di fatto, l'utilizzo successivo di val comporterà una violazione di accesso. Tuttavia, se usiamo l'operatore address-of, in questo modo:

TValue.Make(@AObject, TypeInfo(TMyObject), val); 

tutto è buono. Per me, questo era inaspettato, poiché pensavo che AObject fosse (sotto il cofano) in effetti un puntatore. Ho sbagliato o è una stranezza con il metodo TValue.Make? Qualcuno potrebbe per favore illuminarmi?

risposta

9
procedure Foo; 
var 
    I: Integer; // value type 
    O: TObject; // reference type 
begin 
    @I; // Get a pointer to I 
    O := TObject.Create; 
    @O; // Get a pointer to the memory "behind" the reference O 
end; 
  • La @I posizione così come la posizione di O (riferimento) è in pila.
  • L'ubicazione @O invece è nell'heap.

Normalmente non importa molto, perché il compilatore sa quando effettuare il dereferenziamento e quando no.

Nel caso di TValue.Make la funzione accetta un puntatore.

  • Quando si specifica Make(O..., il compilatore eseguirà il cast rigido del riferimento su un puntatore (che punta allo stack).
  • Quando si specifica Make(@O..., il compilatore innanzitutto annulla e quindi crea un puntatore alla posizione nell'heap.

Quindi si deve dare al compilatore un suggerimento in questo caso, perché non sa quale tipo di puntatore si aspetta il TValue.Make.

+0

grazie mille per un chiaro e una spiegazione succinta! – conciliator

+0

Sottile e fondamentale ... ;-) +1 –

1

Nell'esempio, AObject è un riferimento a un oggetto, non all'oggetto stesso. Questo è il modo per dichiarare il riferimento a un oggetto in Delphi rispetto ad un altro linguaggio in cui è necessario aggiungere esplicitamente refrence o puntatore all'oggetto.

Così AObject o @AObject dovrebbe funzionare lo stesso nel tuo caso, ma come TValue.Make() prendere un puntatore a un buffer nel primo parametro, è necessario fornire Addr(AObject) o @AObject alla funzione.

+1

Ma @conciliator afferma che 'AObject' e' @ AObject' funzionano in modo diverso per lui, sembra contraddire la tua risposta? – Zruty

+0

@TridentT: Devo ammettere che sono ancora confuso. Se 'AObject' e' @ AObject' sono entrambi puntatori, perché si dovrebbe lavorare e non l'altro? Intuitivamente, penserei a '@ AObject' come puntatore a un puntatore. (Ad esempio, dire che mi piacerebbe creare un TValue da un int 'int'. In tal caso, '@ intvar' ha perfettamente senso, ma il caso oggetto mi sconcerta ancora ...) – conciliator

2

L'argomento di ABuffer che si passa a TValue.Make è il puntatore del valore che si desidera memorizzare all'interno di TValue. Non importa se il tipo stesso è un tipo di puntatore o meno. Quindi devi passare il riferimento a AObject anche se AObject stesso è anche un puntatore.

Nell'esempio che hai postato io preferirei usare il TValue.From <T> metodo:

val := TValue.From<TMyObject>(AObject); 

Se il typeinfo non è noto a compiletime è necessario utilizzare TValue.Make - altrimenti TValue.From <T> è più facile da usare.

Problemi correlati