I'm using Delphi 10.3 Community Edition, targeting Windows 32-bit.
I'm writing an interface type. Its class internally uses a TList<T>
(and some other objects). In order to avoid having to write several pass-through one-liner methods, I'm using the implements
keyword to delegate, like this:
program MRE;
{$APPTYPE CONSOLE}
uses
System.Generics.Collections;
type
IMyList = interface
['{8483DB08-57EA-40D0-BFCE-5E39804CA15B}']
function Add (const ACard: Cardinal): Integer;
function GetEnumerator: TList<Cardinal>.TEnumerator;
end;
TMyList = class (TInterfacedObject, IMyList)
constructor Create;
destructor Destroy; override;
private
FCards: TList<Cardinal>;
public
property Cards: TList<Cardinal>
read FCards
implements IMyList;
end;
constructor TMyList.Create;
begin
FCards := TList<Cardinal>.Create;
end;
destructor TMyList.Destroy;
begin
FCards.Free
end;
begin
var Test: IMyList := TMyList.Create;
Test.Add (3);
for var c in Test do
WriteLn (c);
ReadLn
end.
This works fine and prints 3, as expected.
However, when I experienced strange crashes in the more complex version of the program, I was able to distill the bug down to the declaration of a type. Just add a single line (anywhere between the type declarations):
type
TCardList = TList<Cardinal>; { **** this isn't even used anywhere! }
The code still compiles, but the application now crashes with an Access Violation ('write of address 0x004ee838'). It's not just the call to Add()
. When you remove that, it still crashes when the for
loop tries to get the enumerator.
Are there some weird restrictions to delegation that I'm missing here, or could this be a compiler deficiency?
EDIT: As requested in the comments, here is the same code again with the single line that triggers the crash already added:
program MRE;
{$APPTYPE CONSOLE}
uses
System.Generics.Collections;
type
TCardList = TList<Cardinal>; { **** this isn't even used anywhere! }
IMyList = interface
['{8483DB08-57EA-40D0-BFCE-5E39804CA15B}']
function Add (const ACard: Cardinal): Integer;
function GetEnumerator: TList<Cardinal>.TEnumerator;
end;
TMyList = class (TInterfacedObject, IMyList)
constructor Create;
destructor Destroy; override;
private
FCards: TList<Cardinal>;
public
property Cards: TList<Cardinal>
read FCards
implements IMyList;
end;
constructor TMyList.Create;
begin
FCards := TList<Cardinal>.Create;
end;
destructor TMyList.Destroy;
begin
FCards.Free
end;
begin
var Test: IMyList := TMyList.Create;
Test.Add (3);
for var c in Test do
WriteLn (c);
ReadLn
end.
This produces the crash mentioned above.