0

I'm using Delphi 10 Seattle. When I compile this unit (it's just a blank vcl project with a button which has Button1Click registered) it compiles and runs but the data is not as expected. The function Explicit (which overrides the explicit cast) will receive (6109508, -1, 3) instead of (1, 2, 3). Why is that so? The constructor works just fine and it has the same parameter declaration.

When I look at data using the debugger it's (1, 2, 3) but when I step into Explicit and inspect Values it's (6109508, -1, 3). The same is true when Values is not const.

I use TIntArray just to show that this has the same result as TGeneric<integer>.

What am I missing? Or is this a bug?

unit Unit1;

interface
uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
 TGeneric<T: record> = record
  private
    FData:  array of T;
  public
   class operator Explicit(const Values: array of T): TGeneric<T>;
   constructor Create(const Values: array of T);
 end;
   TIntArray = TGeneric<integer>;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

class operator TGeneric<T>.Explicit(const Values: array of T): TGeneric<T>;
begin
  Result :=  TGeneric<T>.Create(Values);
end;

constructor TGeneric<T>.Create(const Values: array of T);
begin
  SetLength(Self.FData, Length(Values));
   Move(Values[0], Self.FData[0], Length(Values) * SizeOf(T));
end;

procedure TForm1.Button1Click(Sender: TObject);
var a : TIntArray;
const data : array of integer = [ 1,2,3 ];
begin
  a := TGeneric<integer>.Create(data); // seems ok.
  a := TIntArray.Create(data); // seems ok.
  a := TGeneric<integer>(data); // sends garbage to Explicit.
  a := TIntArray(data); // sends garbage to Explicit.
end;

end.
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
Claude Martin
  • 745
  • 6
  • 21
  • FWIW, `TGeneric.Create` won't work if `T` is a managed type. For instance a record that contains managed types. In fact your very own `TGeneric` is such a thing. – David Heffernan May 10 '17 at 15:32
  • Bit T is integer or any other "record". Records are not managed. They are values. – Claude Martin May 10 '17 at 17:11
  • We'd have to upgrade to Tokyo to see if it is fixed. I'll just close this now. – Claude Martin May 10 '17 at 17:14
  • Not so. Records are managed if they contain managed types. As I said, your record is itself managed. – David Heffernan May 10 '17 at 18:01
  • Records are not managed. They are values: "Records are value types, so they are copied on assignment, passed by value, and allocated on the stack unless they are declared globally or explicitly allocated using the New and Dispose function." There's nothing to manage. However, when created/disposed there's reference counting going on on all managed types used inside of that record. And this is off topic. – Claude Martin May 12 '17 at 09:13
  • Rubbish. It's as I say. – David Heffernan May 12 '17 at 09:14

1 Answers1

1

This issue has been brought up in another question, was reported and fixed in Delphi 10.2

Community
  • 1
  • 1
Stefan Glienke
  • 20,860
  • 2
  • 48
  • 102