Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Managed Records - initializer fälschlicherweise aufgerufen? (https://www.delphipraxis.net/210065-managed-records-initializer-faelschlicherweise-aufgerufen.html)

TurboMagic 24. Feb 2022 14:26

Managed Records - initializer fälschlicherweise aufgerufen?
 
Hallo,

Problem mit managed records in 10.4.2.
Ich habe einen record und eine generische Liste dieser Records:

Delphi-Quellcode:
type
  TMyRec = record
    Files : TStringlist;
    MyStr : string;

    procedure Clear;

    class operator Initialize(out Dest: TMyRec );
    class operator Finalize(var Dest: TMyRec );
  end;

  /// <summary>
  ///   List of all updates found in the package
  /// </summary>
  TMyList = class(TList<TMyRec>)
und ich habe diese record operators:

Delphi-Quellcode:
procedure TMyRec.Clear;
begin
  Files.Clear;
  MyStr := '';
end;

class operator TMyRec.Finalize(var Dest: TUpdate);
begin
  Dest.ParameterFiles.Free;
  // mein Loggingaufruf
  log.Send(LevelBlue, cCategory, 'Liste freigegeben');
end;

class operator TMyRec .Initialize(out Dest: TUpdate);
begin
  Dest.ParameterFiles := TStringlist.Create;
  log.Send(LevelBlue, cCategory, 'Liste erzeugt');
end;
Woanders in einer Klasse im Code habe ich ein Listenfeld und eine Methode die
etwas verarbeitet:

Delphi-Quellcode:
type
  TMyClass = class(TObject)
  private
    FMyList : TMyList;
    procedure DoIt;
  end;
[..]

procedure TMyClass.DoIt;
var
  Rec: TMyRec;
begin
  Rec.MyStr := 'Test';
  FMyList.Add(Rect);
end;
Lt. diesem Blogpost einer authritativen Quelle:
https://blogs.embarcadero.com/custom...o-delphi-10-4/
bin ich der Meinung, dass FMyList.Add(Rect); den Initializer von TMyRec nicht aufrufen sollte, da
Add in Generics.Collections ein const vor dem Parameter stehen hat und das dann ja wie im Blogpost unter "Passing Managed Records as Parameters"
geschildert ein ParByConstValue sein müsste.

Nur mein Log und auch der Debugger die sagen etwas anderes.
Hat jemand eine Idee?

Grüße
TurboMagic

peterbelow 24. Feb 2022 14:50

AW: Managed Records - initializer fälschlicherweise aufgerufen?
 
Zitat:

Zitat von TurboMagic (Beitrag 1502657)
Hallo,

Problem mit managed records in 10.4.2.

Delphi-Quellcode:
type
  TMyClass = class(TObject)
  private
    FMyList : TMyList;
    procedure DoIt;
  end;
[..]

procedure TMyClass.DoIt;
var
  Rec: TMyRec;
begin
  Rec.MyStr := 'Test';
  FMyList.Add(Rect);
end;
Lt. diesem Blogpost einer authritativen Quelle:
https://blogs.embarcadero.com/custom...o-delphi-10-4/
bin ich der Meinung, dass FMyList.Add(Rect); den Initializer von TMyRec nicht aufrufen sollte, da
Add in Generics.Collections ein const vor dem Parameter stehen hat und das dann ja wie im Blogpost unter "Passing Managed Records as Parameters"
geschildert ein ParByConstValue sein müsste.

Nur mein Log und auch der Debugger die sagen etwas anderes.

Der Code macht keinen Sinn, es sei denn Du meintest
Delphi-Quellcode:
  FMyList.Add(Rec);
und nicht Rect. Es ist nicht dieses Statement das den Initializer aufruft sondern das davor, eventuell auch einfach die Deklaration der lokalen Variablen selbst.

TurboMagic 24. Feb 2022 14:58

AW: Managed Records - initializer fälschlicherweise aufgerufen?
 
Hallo,

danke für die Antwort.

1. Ja, das muss FMyList.Add(Rec); heißen

2. Mit deiner anderen Vermutung liegst du aber leider falsch!
Der Initializer wird einmal beim Betreten der Methode aufgerufen,
weil es ja diese lokale Variable gibt: Rec: TMyRec;
Aber: er wird auch durch FMyList.Add(Rec); nochmal aufgerufen!
Was ich als falsch empfinde!

Grüße
TurboMagic

Uwe Raabe 24. Feb 2022 15:07

AW: Managed Records - initializer fälschlicherweise aufgerufen?
 
Zitat:

Zitat von TurboMagic (Beitrag 1502659)
Aber: er wird auch durch FMyList.Add(Rec); nochmal aufgerufen!
Was ich als falsch empfinde!

Bei dem Add wird ja eine Kopie des Records an die Liste angefügt. Andernfalls würden ja folgende Änderungen an Rec auch in der Liste gespeicherte Element verändern.

TurboMagic 24. Feb 2022 15:36

AW: Managed Records - initializer fälschlicherweise aufgerufen?
 
Ok, aber inzwischen hab' ich nochwas ganz unerklärliches.
Diese Methode:

Delphi-Quellcode:
function TMyList.GetSelectedWhatever: UInt8;
begin
  Result := 0;

  for var MyRec in self do
    if MyRec.IsSelected then
      inc(Result);
end;

procedure TMyList.DoSomething;
begin
end;
die ja zu einem Objekt dieses Typs TMyList = class(TList<TMyRec>) gehört
springt beim Debuggen sobald ich die for Schleife erreiche in eine ganz
andere normale public methode DoSomething; und zwar mitten in die Methode!
Das sieht total falsch abgebogen und nach Bug aus! Ich kann nur meinen Code
nicht teilen.

Grüße
TurboMagic

TurboMagic 24. Feb 2022 15:55

AW: Managed Records - initializer fälschlicherweise aufgerufen?
 
Ok, mein letzter Post stellte sich als falsch heraus, da war der Debugger schuld,
der mal wieder gesetzte Breakpoints vergessen hat.

Aber im Freigeben der Stringliste im Finalizer krachts trotzdem noch mit "invalid pointer".

Der schöne Günther 24. Feb 2022 16:33

AW: Managed Records - initializer fälschlicherweise aufgerufen?
 
Kannst du nicht einmal alles möglichst kurz zum Nachstellen in die .DPR oder eine .pas-Datei packen? Dann kann das jeder bei sich direkt ausprobieren.

TurboMagic 25. Feb 2022 17:58

AW: Managed Records - initializer fälschlicherweise aufgerufen?
 
Danke, ich habe das jetzt auf eine normale Klasse und eine TBojectList<T> umgebaut und
inzwischen alle dadurch zugezogenen Problemchen beseitigt (glücklicherweise hatte ich
für einiges Unit tests) und werde daher gerade kein testprogrämmchen schreiben.

Evtl. schaue ich mir das bei gelegenheit nochmal mit einer Minimaldemo an...


Alle Zeitangaben in WEZ +1. Es ist jetzt 01:36 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz