3

I realise this is a contrived example but the following code causes a memory leak in Delphi XE2 (and maybe other versions).

type
  TTest =record
    a :string;
    procedure SetA;
  end;

procedure TTest.SetA;
begin
  a:='Test';
end;

procedure TfrmMain.btGoClick(Sender: TObject);
var
  t :TTest;

  procedure SetA(const Rec: TTest);
  begin
    Memo.Lines.Add(IntToStr(NativeInt(@Rec)));

    Rec.SetA;
  end;

begin
  Memo.Lines.Add(IntToStr(NativeInt(@t)));

  SetA(t);

  if t.a='' then
    Memo.Lines.Add('t.a: (empty)')
  else
    Memo.Lines.Add('t.a: '+t.a);
end;

The source of the memory leak is the setting of a in TTest.SetA, the string is never released.

The output of the above is:

1700728
1700688
t.a: (empty)

From this we can see that even though the record parameter is passed as a const the address of Rec is different from the main variable t.

Now if I change the record type definition to:

  TTest =record
    a :string;
    a1 :string;
    a2 :string;
    a3 :string;
    procedure SetA;
  end;

The output is now:

1700712
1700712
t.a: Test

So the same address of Rec and t, also t.a has been set, also no memory leak.

I have tried to look at the CPU but have a hard time seeing the difference when the dummy a1, a2 and a3 variables are added.

Obviously all this can be avoided by making the parameter to SetA a var parameter, but the reason for this question is to try and understand what the compiler is doing in the two different situations.

So what is going on here?

AJ.
  • 10,732
  • 13
  • 41
  • 50
  • When the record is small enough, it is passed by value. When it is larger, it is passed by reference. Anyway you're not supposed to modify `Rec` when you use `const`. – Olivier Aug 29 '21 at 08:48
  • @Olivier, yes that makes sense, do you know the minimum size of a record before it is passed by reference? I realise you are not meant to modify if a const, that's why it's a contrived example. – AJ. Aug 29 '21 at 08:53
  • I guess the limit is the size of a pointer. – Olivier Aug 29 '21 at 08:56
  • Also see [this](https://stackoverflow.com/questions/40929338/is-the-ref-attribute-for-const-record-parameters-useful) about the `[Ref]` attribute. – Olivier Aug 29 '21 at 09:15
  • @Olivier, thanks for the link about [Ref], I had no idea that const records could be passed by value if small enough, very esoteric! – AJ. Aug 29 '21 at 09:22
  • 1
    The real problem is the poor language design that allows methods on records to modify self, which when combined with const params means you can circumvent the constness. – David Heffernan Aug 29 '21 at 14:25

0 Answers0