0

I am creating several TPoint objects at runtime but I am not destroying them.

I checked the code of TPoint in System.Types:

PPoint = ^TPoint;
  TPoint = record
    X: FixedInt;
    Y: FixedInt;
  public
    constructor Create(P : TPoint); overload;
    constructor Create(const X, Y : Integer); overload;

    //operator overloads
    class operator Equal(const Lhs, Rhs : TPoint) : Boolean;
    class operator NotEqual(const Lhs, Rhs : TPoint): Boolean;
    class operator Add(const Lhs, Rhs : TPoint): TPoint;
    class operator Subtract(const Lhs, Rhs : TPoint): TPoint;

    class operator Implicit(Value: TSmallPoint): TPoint;
    class operator Explicit(Value: TPoint): TSmallPoint;

    class function PointInCircle(const Point, Center: TPoint; const Radius: Integer): Boolean; static; inline;
    /// <summary> Zero point having values of (0, 0). </summary>
    class function Zero: TPoint; inline; static;

    function Distance(const P2 : TPoint) : Double;

    procedure SetLocation(const X, Y : Integer); overload;
    procedure SetLocation(const P : TPoint); overload;
    procedure Offset(const DX, DY : Integer); overload;
    procedure Offset(const Point: TPoint); overload;
    function Add(const Point: TPoint): TPoint;
    function Subtract(const Point: TPoint): TPoint;
    function IsZero : Boolean;

    function Angle(const APoint: TPoint): Single;
  end;

By reading it i see there is no destructor and moreover it is a record of primitives. I do not master Delphi at a point to be sure about it, but i think it is not needed to call MyPoint.Free. May some expert confirm?

Wolf
  • 9,679
  • 7
  • 62
  • 108
UnDiUdin
  • 14,924
  • 39
  • 151
  • 249
  • 1
    You shouldn't be able to even compile `MyPoint.Free`. – Sebastian Proske Apr 28 '17 at 06:53
  • A record is a value type, which means that it does not need to be deallocated. Record fields that are heap allocated needs to be deallocated though. The compiler handles deallocation of managed types, but classes for example must be deallocated explicitly. – LU RD Apr 28 '17 at 06:54
  • The real problem is that the type has a constructor. That just confuses you. Emba made a bad decision pushing out lots of types like that. – David Heffernan Apr 28 '17 at 10:53

2 Answers2

6

TPoint is a record.

value types
Record and basic types like integer are value types.
This means that they are created on the stack.
When a function exits it cleans up the stack and by so doing reclaims the memory space.

reference types
This is in contrast to classes which are reference types.
A class is created on the heap and needs to be explicitly freed.

managed types
Right in between these two extremes sit managed types like string or interface.
These are created on the heap, but the compiler uses compiler magic to automatically destroy them when their reference count drops to zero. Because of this managed types are said to have value sementics.

ARC
On ARC compilers (mobile + Linux) even classes are automatically managed using reference counting. This means that the semantic differences between records, classes and managed types have been eliminated.

You can of course create a record on the heap if you want:

type
  PRecord = ^TMyRecord;
var
  HeapRec: PRecord;
begin
  GetMem(HeapRec, SizeOf(TMyRecord));
  try
    do stuff with HeapRec........
  finally
   FreeMem(HeapRec);

Remember to always pass records as const parameters (if possible). Otherwise the compiler will waste time making a copy of the record.

But.... methods?
Records have methods these days.
However this is merely syntactic sugar.
You cannot have virtual/dynamic methods and you cannot have interfaced methods

The following two methods are exactly equivalent:

//Pre Delphi 2006
function CloneTMyRecord(const Self: TMyRecord): TMyRecord;

//Post Delphi 2006
function TMyRecord.Clone: TMyRecord;
Johan
  • 74,508
  • 24
  • 191
  • 319
1

TPoint is not a class.

What convinced me is that I was trying to do an objectlist defined like this:

uses Generics.Collections;
//
PointsList: TObjectList<TPoint>;

and the compiler told me

"E2511 Type parameter 'T' must be a class type"

so this convinced me that TPoint is not an object and therefore must not be freed. Moreover about storing TPoint in a List this thread describes a better use of Generics with TList: store array of TPoint inside TObjectList. In fact a list of TPoint is safely defined as TList<TPoint>.

Moreover I tried to search leaks with Eurekalog and non freed TPoint is not giving leak as a non freed TStringList does.

By the way, also the fact that TPoint is defined in System.Types could have been replied to my question "Is TPoint a primitive in Delphi?"

Wolf
  • 9,679
  • 7
  • 62
  • 108
UnDiUdin
  • 14,924
  • 39
  • 151
  • 249
  • 2
    The simplest way to find out whether it is a class is looking at the declaration in the RTL source code which comes with every Delphi version (... that is not a test version). In Delphi 2007 its: TPoint = packed record X: Longint; Y: Longint; end; – dummzeuch Apr 28 '17 at 09:30
  • TObjectList is specific to TObject descendants. It owns its items, so it will dispose them when the list disposed (composition). Use List for primitive types or when you don't want the list to own its items. – The Bitman Apr 28 '17 at 11:50
  • The documentation already tells you that `TPoint = record`, and a `record` is not a class instance. That says it all, and *that* should have convinced you. – Rudy Velthuis Apr 29 '17 at 04:13
  • Hopefully I met your intent by tweaking question and answer, BTW *TPoint is not a class* and *TPoint is not an object* look a bit strange (together). – Wolf Jul 16 '21 at 13:25