Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Weak-TList ? (https://www.delphipraxis.net/184100-weak-tlist.html)

himitsu 25. Feb 2015 23:09

Delphi-Version: XE7

Weak-TList ?
 
Tachchen.

Delphi-Quellcode:
var
  [Weak] Variable: IInterface;
  [Weak] Liste: TList<IInterface>;
  Liste: TList<[Weak] IInterface>; // geht nicht - Error-Insight und Compiler sagen nein
Die Variable wäre jetzt ohne Referenzzählung, im NextGen-Compiler,
aber wie definiert man eigentlich eine Liste mit Weak-Referenzen?

Bei
Delphi-Quellcode:
[Weak] Liste: TList<IInterface>;
ist natürlich (nur?) die Liste-Variable ohne Referenzzählung, aber nicht der Listeninhalt. So würde ich die OH verstehen tun.

Kann es leider nicht ausprobieren und die Compiler sind diesbezüglich echt doof und geben keinerlei Meldungen/Fehlermeldungen, ob Attribute richtig sind oder ob sie es nicht sind.
Nichtmal bei Denen, die den Compiler und den erzeugten Code/Typen/RTTI selber betreffen. :wall:

Die Hilfe sagt natürlich rein garnichts, zu [Weak] bei Typen. Und in der Hilfe zum WeakAttribute steht wirklich GARNICHTS (nur der bekannte nichtssagende Schrott).

Delphi-Quellcode:
type
  IWeakInterface = [Weak] IInterface; // Hier sträubt sich das Error-Insight und der Compiler.
  [Weak] IWeakInterface = IInterface; // Geht das?
  [Weak] IWeakInterface = type IInterface; // Und ist das richtig?

var
  Liste: TList<IWeakInterface>;

Daniel 26. Feb 2015 06:55

AW: Weak-TList ?
 
Zitat:

Zitat von himitsu (Beitrag 1291564)
aber wie definiert man eigentlich eine Liste mit Weak-Referenzen?

Eigene Listen-Klasse mit eigenem Listen-Objekt, welches seinerseits die weak-Referenz auf Deine Interfaces beinhaltet und entsprechend kommunizieren kann, ob da noch etwas ist oder nicht.

Stevie 26. Feb 2015 07:39

AW: Weak-TList ?
 
Delphi-Quellcode:
program WeakRefListTests;

uses
  TestFramework,
  TestInsight.DUnit,
  Spring,
  Spring.Collections;

type
  TWeakRefListTest = class(TTestCase)
  published
    procedure ListDoesNotKeepStrongReference;
  end;

  IRefCounted = interface
    function GetRefCount: Integer;
    property RefCount: Integer read GetRefCount;
  end;

  TRefCounted = class(TInterfacedObject, IRefCounted);

procedure TWeakRefListTest.ListDoesNotKeepStrongReference;
var
  sut: IList<WeakReference<IRefCounted>>;
  ref: IRefCounted;
begin
  sut := TCollections.CreateList<WeakReference<IRefCounted>>;
  ref := TRefCounted.Create;
  sut.Add(ref);
  CheckEquals(1, ref.RefCount);
  ref := nil;
  CheckFalse(sut[0].IsAlive);
  ref := sut[0];
  CheckNull(ref);
end;

begin
  RegisterTest(TWeakRefListTest.Suite);
  RunRegisteredTests();
end.

himitsu 26. Feb 2015 09:44

AW: Weak-TList ?
 
Nja, dachte daß Delphi sowas auch selber kann. :roll:

Die [Weak]-Referenzen werden doch auch nicht auf nil gesetzt, sondern sind dann einfach nur "ungültige" Zeiger.
Aber das Problem gibt es nicht, da sich die Interfaces selber überall raus löschen, wenn sie freigegeben werden. (die kennen die Gegenseite, da sie selber eine gezählte Referenz besitzen, oder sie kennen wen, der den kennt)

Nur dürfen diese Referenzen halt nicht gezählt werden, damit sie sich freigeben können.

Für einzelne Variablen und Felder geht das Einfach, aber wie man das für Listen/Arrays deklariert, ist nirgendwo beschrieben, obwohl es irgendwie gehen soll.

Daniel 26. Feb 2015 09:46

AW: Weak-TList ?
 
Zitat:

Zitat von himitsu (Beitrag 1291581)
Die [Weak]-Referenzen werden doch auch nicht auf nil gesetzt, sondern sind dann einfach nur "ungültige" Zeiger.

ehm. Na doch. Das ist doch gerade der Witz an einem Weak-Pointer. Der kennt nur zwei stabile Zustände: "Gültige Referenz" oder "NIL".

Sir Rufo 26. Feb 2015 09:48

AW: Weak-TList ?
 
Dazu hatten wir schon was :)

http://www.delphipraxis.net/183253-a...nicht-arc.html

himitsu 26. Feb 2015 09:54

AW: Weak-TList ?
 
Im ARC wollte ich mal versuchen das möglichst alles "nativ" zu belassen. :stupid:

Sir Rufo 26. Feb 2015 10:03

AW: Weak-TList ?
 
Zitat:

Zitat von himitsu (Beitrag 1291586)
Im ARC wollte ich mal versuchen das möglichst alles "nativ" zu belassen. :stupid:

Was hat das mit "nativ" zu tun?

Hier mal ein Beispiel, wo so eine WeakRef-Record für ARC sinnvoll verwendet werden kann:
Delphi-Quellcode:
function Foo( const ABitmap : TBitmap ):ITask;
var
  LBitmapRef: WeakRef<TBitmap>;
begin
  // WeakRef auf Bitmap
  LBitmapRef := ABitmap;
  Result := TTask.Create( 
    procedure
    var
      LBitmap : TBitmap;
    begin
      // StrongRef auf Bitmap, damit die bis zum Ende des Tasks überlebt, wenn es die noch gibt :o)
      LBitmap := LBitmapRef;
      // Wenn Bitmap schon weg ist, dann raus hier
      if not Assigned( LBitmap ) then Exit;
      // Now work on Bitmap
     
    end );
end;
Du erzeugst also einen Task, der irgendwann gestartet werden soll. Die übergebene Bitmap kann aber bis zum echten Start schon wieder verschwunden sein. Ist die Bitmap beim Starten aber nicht verschwunden, dann wird im Task wieder eine Strong-Ref auf Bitmap gemacht und schon lebt die Referenz bis zum Ende des Tasks.

himitsu 26. Feb 2015 10:31

AW: Weak-TList ?
 
Mit "nativ" meinte ich "Nur mit den Mitteln dessen, was Delphi selber kann", also ohne Fremdkomponenten und möglichst ohne viel selbst zu basteln.

Die ersten Beiden sollten schon funktionieren (zumindestens im NextGen/WEAKINTREF),
Delphi-Quellcode:
type
  TParent = class(TInterfacedObject, IParent)
    FChild: IChild;
  end;

  TChild = class(TInterfacedObject, IChild)
    [Weak] FParent: IParent;
  end;
Delphi-Quellcode:
type
  TParent = class(TInterfacedObject, IParent)
    FChilds: TList<IChild>;
  end;

  TChild = class(TInterfacedObject, IChild)
    [Weak] FParent: IParent;
  end;
aber hier hängt es, also wie man das genau "definiert".
Delphi-Quellcode:
type
  TParent = class(TInterfacedObject, IParent)
    FLink: ILink;
  end;

  TLink = class(TInterfacedObject, ILink)
    FParents: TList<[Weak] IParent>;
  end;
Wenn Delphi das dann in den nächsten 20 Jahren endlich mal in allen Compileren richtig drin hat,
(k.A. warum man [Weak] für Interfaces nicht überall eingebaut hat :wall:)
dann wäre jetzt kein weiterer Code mehr nötig.

himitsu 11. Mär 2015 00:45

AW: Weak-TList ?
 
Ich hatte nun 'ne ganze Weile versucht damit einen "ordentlichen" Code hinzubekommen, welcher auf allen Platformen richtig funktioniert.

Also mit den aktuellen/alten Möglichkeiten der Delphi-Compiler
Delphi-Quellcode:
[Weak]
,
Delphi-Quellcode:
[Unsafe]
,
Delphi-Quellcode:
[Ref]
und
Delphi-Quellcode:
[Volatile]
.
Den Blick in OH/Dokwiki könnt ihr vergessen, denn bei den Attributen ist nichts zu finden, aber es gibt einen anderen etwas versteckteren Hilfe-Eintrag dazu. (verlinken können die sowas natürlich nicht)



Fazit: Alles Mist und ich caste die Rückreferenzen nun überall nur noch selbst als Pointer.

Für "einfache" 1:1-Kreuzverlinkungen mit einfachen Variablen ist
Delphi-Quellcode:
[Weak]
und
Delphi-Quellcode:
[Unsafe]
im ARC allerdings ganz praktisch, auch wenn es keine richtig nicht-referenzgezählten Variablen gibt, wo es absolut keine Behandlung von Referenzen gibt.
Aber sobald Listen oder kompliziertere n:n-Verlinkungen ins Spiel kommen, ist es nahezu unmöglich einen "nativen" Code zu schreiben, der wirklich überall läuft und das auch nur mit ausreichenden IFDEFs oder über Fremdkomponenten.

Wenn ich bissl aufgeräumt und alles nochmal durchgelesen hab, dann werde ich demnächst mal meine Testanwendung/Testcode/Artikel für diese beiden "schwachen Referenzen" hochladen.

Leider gibt es
Delphi-Quellcode:
[Weak]
,
Delphi-Quellcode:
[Unsave]
und
Delphi-Quellcode:
[NoRefCount]
nicht in allen Platformen.
https://quality.embarcadero.com/browse/RSP-10135
Im Grunde ist das der Grund, warum ich einige Komponenten nun komplett und umständlich (da doppelte Deklarationen usw.) auf Interfaces umstelle, damit sie überall funktionieren und überall gleich benutzbar sind.
Grade bei den Interfaces gibt es nun, dank
Delphi-Quellcode:
[Weak]
und AutoRefCount (für interne Objekte), dennoch standardmäßig kein gleiches Verhalten, außer man sorgt selber auf brutalste Weise dafür. :wall:
(nur Interfaces ohne irgendwelche Objektreferenzen und ohne schwachen Referenzen arbeiten wirklich überall gleich)


Alle Zeitangaben in WEZ +1. Es ist jetzt 19:47 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