Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does TValue.Make require a pointer to an object reference?

I've always been under the impression that objects in Delphi are in fact references to memory locations, which in turn I've imagined were stored as pointer variables.

Now, I want to make a TValue from an object. Consider this:

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

where val: TValue. This won't work. In fact, subsequent usage of val will lead to an access violation. However, if we use the address-of operator, like so:

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

all is good. For me, this was unexpected, as I thought AObject was (under the hood) in fact a pointer. Am I wrong or is this a quirk with the TValue.Make method? Could someone please enlighten me?

like image 491
conciliator Avatar asked Nov 07 '11 10:11

conciliator


3 Answers

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;
  • The location @I as well as the location of O (the reference) is on the stack.
  • The location @O on the other hand is on the heap.

Normally that doesn't matter much, because the compiler knows when to dereference and when not to.

In the case of TValue.Make the function takes a pointer.

  • When you specify Make(O... the compiler will hard cast the reference to a pointer (which points to the stack).
  • When you specify Make(@O... the compiler will first dereference and then create a pointer to the location on the heap.

So you have to give the compiler a hint in this case, because it doesn't know which kind of pointer the TValue.Make expects.

like image 143
Jens Mühlenhoff Avatar answered Oct 22 '22 18:10

Jens Mühlenhoff


The ABuffer argument you pass to TValue.Make is the pointer to the value you want to store inside the TValue. It does not matter if the type itself is a pointer type or not. So you have to pass the reference to AObject even if AObject itself is also a pointer.

In the example you posted I would prefer to use the TValue.From<T> method:

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

If the typeinfo is not known at compiletime you have to use TValue.Make - otherwise TValue.From<T> is easier to use.

like image 3
Stefan Glienke Avatar answered Oct 22 '22 16:10

Stefan Glienke


In your example, AObject is a reference to an object, not the object itself. This is the way to declare object reference in Delphi as opposed to other language where you must explicitly add refrence or pointer to the object.

So AObject or @AObject should work the same in your case, but as TValue.Make() take a pointer to a buffer in the first parameter, you should provide Addr(AObject) or @AObject to the function.

like image 1
TridenT Avatar answered Oct 22 '22 16:10

TridenT