1

I have a beginner question using pointers in delphi.

I create an object and save it's address in a variant variable. But I dont know how to access the object using this variable. Here's my code:

...
      New(PSplObj);
      PSplObj^ := TsplCellObject.Create;
      PSplObj.description := sTeam;
      PSplObj.color := clRed;
      myvar := Integer(PSplObj);
      dispose(PSplObj);

      // how to access the object throug the pointer in myvar?
...
Gregor Brandt
  • 7,659
  • 38
  • 59
gonzales
  • 401
  • 1
  • 9
  • 20
  • 1
    The first problem is that you're disposing the object that you're trying to reference later. That definitely won't work. – Chris Thornton May 10 '11 at 17:32
  • 1
    actually disposing a pointer to the object reference. But there's no need for explicit heap allocation here. – David Heffernan May 10 '11 at 17:34
  • 1
    This is a super-ultra-very-bad-no-good idea. – Warren P May 10 '11 at 17:55
  • this question is probably a twisted duplicate of this one: http://stackoverflow.com/questions/5302768/convert-olevariant-to-object-in-delphi – yms May 10 '11 at 18:03
  • Why do you want to do this? Also "PSplObj^:=TsplCellObject.Create;": I assume PSplObj is a pointer - if so you are deferencing the pointer before you've assigned it?! Did you mean PSplObj:=TsplCellObject.Create? See @mason's answer - I think you need to rethink your approach. – Vector May 10 '11 at 18:49

2 Answers2

3

I think your main problem relates to what a Delphi object reference is. Consider the following artificial example:

type
  TMyRecord = record
    a, b, c: Integer;
  end;
  TMyClass = class
    a, b, c: Integer;
  end;
... 
var
  MyRecord: TMyRecord;
  MyObject: TMyObject;
...
MyObject := TMyObject.Create;

At this point we have instances of two, essentially identical, structured types. However, the way Delphi presents these instances is quite different. The record is what is known as a value type and the object is a reference type.

When you assign to a variable of a reference type, the value is copied. For example:

MyRecord2.a := 1;
MyRecord1 := MyRecord2;
MyRecord1.a := 2;
Assert(MyRecord1.a<>MyRecord2.a);

Examples of value types include integers, enumerated types, floating point types, records, objects etc.

In contrast, assigning to a reference type variable copies the reference so that both variables refer to the same object. For example:

MyObject2.a := 1;
MyObject1 := MyObject2;
MyObject1.a := 2;
Assert(MyObject1.a=MyObject2.a);

One feature of reference types is that they are all heap allocated, whereas value types can be either heap or stack allocated.

Examples of reference types include classes, interfaces, dynamic arrays.

Delphi strings are a funny hybrid. Although they are implemented as references, copy-on-write makes them behave like value types.

Delphi's syntax for objects hides the fact that they are implemented as a reference, i.e. a pointer.

Assert(SizeOf(MyRecord)=3*SizeOf(Integer));//=12
Assert(SizeOf(MyObject)=SizeOf(Pointer));//=4 (or 8 in Delphi 64)

What all this means is that your code is needlessly complicated. There is no need for you to allocate storage for an object reference since an object variable is already a reference. You can write it like this:

//assign object reference to Variant
MyVariant := NativeInt(MyObject);

//extract object reference from Variant
NativeInt(MyObject) := MyVariant;

Note that I am using NativeInt since it is an integer type that is defined to be at least the same size as a pointer. This will become relevant when the 64 bit version of Delphi appears.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Hi David, thank you so much for your explanation. The appreach I've posted was from devExpress (http://www.devexpress.com/Support/Center/p/Q131684.aspx) - so I was sure it was a "good" ^^ – gonzales May 11 '11 at 06:02
2

First off, you don't really need a pointer to your object, because the object itself is already a reference type, and you can cast your object reference to integer (though NativeInt might be better.) To use it, you have to get the integer back out of the variant and cast it back to your pointer/object type, like so:

var
  intref: NativeInt;
  cell: TsplCellObject;
begin
  intref := myvar;
  cell := TsplCellObject(intref);
  //do something with Cell here
end;
Mason Wheeler
  • 82,511
  • 50
  • 270
  • 477