TList, Vorteil ?

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Mathias
Beiträge: 6164
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

TList, Vorteil ?

Beitrag von Mathias »

Ich habe mir TList ein wenig genauer angeguckt, aber ich sehe keinen Vorteil gegenüber einer dynamischen Array.
Ich habe das Gefühl, das mit TList gut Fehler eingebaut werden können, das man mit New und Dispose alles selber machen muss.
Bei der Array mache ich SetLength(xxx, 0) und alles ist aufgeräumt.

Code: Alles auswählen

  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
    List: TList;
  end;
 
  PVector = ^TVector;
  TVector = array[0..2] of single;
 
var
  Form1: TForm1;
 
 
implementation
 
{$R *.lfm}
 
{ TForm1 }
 
procedure TForm1.FormCreate(Sender: TObject);
begin
  List := TList.Create;
end;
 
procedure TForm1.Button1Click(Sender: TObject);
const
  z: integer = 0;
var
  v: PVector;
begin
  Inc(z);
  New(v);
  WriteLn(z);
  v^[0] := 0;
  v^[1] := z;
  v^[2] := 0;
  List.Add(v);
end;
 
procedure TForm1.Button2Click(Sender: TObject);
var
  v: PVector;
  i: Integer;
begin
  for i := 0 to List.Count - 1 do begin
    v := List.Items[i];
    WriteLn(v^[1]);
  end;
end;
 
procedure TForm1.FormDestroy(Sender: TObject);
var
  v: PVector;
  i: Integer;
begin
  for i := 0 to List.Count - 1 do begin
    v := List.Items[i];
    Dispose(v);
  end;
  List.Free;
end;   
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: TList, Vorteil ?

Beitrag von wp_xyz »

- TList kann man erweitern ohne das "Array" neu dimensionieren zu müssen.
- TList hat eine eingebaute Sortierfunktion.
- Wenn die gespeicherten Pointer Objekte sind, musst du diese auch nicht explizit zerstören, falls du den Nachfahren TObjectList verwendest.

marcov
Beiträge: 1100
Registriert: Di 5. Aug 2008, 09:37
OS, Lazarus, FPC: Windows ,Linux,FreeBSD,Dos (L trunk FPC trunk)
CPU-Target: 32/64,PPC(+64), ARM
Wohnort: Eindhoven (Niederlande)

Re: TList, Vorteil ?

Beitrag von marcov »

wp_xyz hat geschrieben: falls du den Nachfahren TObjectList verwendest.


(UND dessen Property ownsobject gesetzt ist)

Benutzeravatar
theo
Beiträge: 10467
Registriert: Mo 11. Sep 2006, 19:01

Re: TList, Vorteil ?

Beitrag von theo »

marcov hat geschrieben:
wp_xyz hat geschrieben: falls du den Nachfahren TObjectList verwendest.


(UND dessen Property ownsobject gesetzt ist)


Was "by default" der Fall ist.

Patito
Beiträge: 203
Registriert: Di 22. Sep 2009, 13:08
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit

Re: TList, Vorteil ?

Beitrag von Patito »

TList vs. dynamische Arrays...

Listenklassen haben gegenüber dynamischen Arrays den Vorteil, dass man (ggf. in abgeleiteten Klassen)
passende Methoden schreiben kann, die man für die Liste brauche. (Suchen, einfügen, Initialisieren, ...).

- TList selber verwende ich eher überhaupt nicht.
- TObjectList verwende ich sehr oft. (oft mit einer Wrapper-Klasse drumrum, die die Zugriffe typsicher macht und die ganzen unnötigen Methoden versteckt)
- Am häufigsten verwende ich selber geschriebene Listenklassen.
- dynamische Arrays kommen bei mir nur in sehr sehr altem Code vor.

Wenn man es einmal gewohnt ist bei Bedarf einfach eine passende Listenklassen mit den passenden Methoden aus dem eigenen Baukasten zu nehmen,
will man sich das Gefummel mit den dynamischen Arrays nicht mehr antun.

(-> Objektorientierung vs. Altsteinzeit)

Benutzeravatar
theo
Beiträge: 10467
Registriert: Mo 11. Sep 2006, 19:01

Re: TList, Vorteil ?

Beitrag von theo »

Generics könnte man auch noch erwähnen.
Hier gibt es ein Beispiel viewtopic.php?p=75357#p75357

http://www.freepascal.org/docs-html/ref/refch8.html

mschnell
Beiträge: 3444
Registriert: Mo 11. Sep 2006, 10:24
OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
CPU-Target: X32 / X64 / ARMv5
Wohnort: Krefeld

Re: TList, Vorteil ?

Beitrag von mschnell »

Mathias hat geschrieben:aber ich sehe keinen Vorteil gegenüber einer dynamischen Array.


Von Arrays kann man keine neuen Klassen ableiten und fpc ist schließlich - und aus guten Grund - eine Objekt-Sprache. Man sollte also - sofern das keine signifikanten Nachteile hat - möglichst alles was irgendwie komplex ist als Klassen verwalten.

(Theoretisch könnte man auch alles in Assembler schreiben :twisted: ....)

Dynamisch Arrays sind - anders als Klassen - "reference counted". Das kann Vorteile haben, birgt aber auch Gefahren.

Dynamisch Arrays sind - anders als Strings - nicht "copy on write". Das kann durchaus verwirren.

-Michael

Mathias
Beiträge: 6164
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: TList, Vorteil ?

Beitrag von Mathias »

Ich sehe langsam der Sinn von TList, bei komplexen Sachen hat es sicher Vorteile.

Was in FP fehlt, ist ein vector.h wie in C++, damit kann man Array sehr komfortabel verwalten.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Scotty
Beiträge: 768
Registriert: Mo 4. Mai 2009, 13:24
OS, Lazarus, FPC: Arch Linux, Lazarus 1.3 r44426M FPC 2.6.4
CPU-Target: x86_64-linux-qt/gtk2
Kontaktdaten:

Re: TList, Vorteil ?

Beitrag von Scotty »

Mathias hat geschrieben:Ich sehe langsam der Sinn von TList, bei komplexen Sachen hat es sicher Vorteile.

Welche Vorteile gibt es bei dynamischen Arrays? Einfacher, übersichtlicher, kürzer?

aList:=TList.Create; //1x
aList.Add('Hello World');

vs.

setlength(aList,length(aList)+1) //jedes mal
aList[length(aList)]:='Hello World';

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: TList, Vorteil ?

Beitrag von mse »

Ich verwende dynamische Arrays sehr häufig, TList und Konsorten aus Performance-Gründen praktisch nie.
Für das bequeme Arbeiten mit dynarrays habe ich die unit msearrayutils gemacht, welche Sortierung und ähnliches zur Verfügung stellt.
Wenn dynamische Arrays nicht mehr ausreichen, verwende ich die Listenklassen aus den units msedatalist und mselist. Die sind aber nicht Delphi-kompatibel und beruhen nicht auf TList.

Mathias
Beiträge: 6164
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: TList, Vorteil ?

Beitrag von Mathias »

Code: Alles auswählen

aList:=TList.Create; //1x
aList.Add('Hello World');

Hier geht es sicher um TStringList, das ist sicher eine der meistgenutzen Listen.

Bei mir ging es eigentlich um die nackte TList.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Mathias
Beiträge: 6164
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: TList, Vorteil ?

Beitrag von Mathias »

Bei Sort gibt es einen Compilerfehler, wieso ?

Code: Alles auswählen

unit1.pas(99,31) Error: Incompatible type for arg no. 1: Got "<procedure variable type of function(Pointer,Pointer):LongInt of object;Register>", expected "<procedure variable type of function(Pointer,Pointer):LongInt;Register>"



Code: Alles auswählen

unit Unit1;
 
{$mode objfpc}{$H+}
 
interface
 
uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls;
 
type
  PVector = ^TVector;
  TVector = array[0..2] of single;
 
  { TVecList }
 
  TVecList = class(TList)
  private
    function AVecCompare(Item1, Item2: Pointer): integer;
  public
    procedure Add(v: TVector);
    procedure Clear; override;
    procedure Insert(Index: integer; v: TVector);
    procedure Sort;
  end;
 
  { TForm1 }
 
  TForm1 = class(TForm)
    Add: TButton;
    Ausgabe: TButton;
    Sort: TButton;
    Insert: TButton;
    procedure AddClick(Sender: TObject);
    procedure AusgabeClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure InsertClick(Sender: TObject);
    procedure SortClick(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
    VecList: TVecList;
  end;
 
var
  Form1: TForm1;
 
 
implementation
 
{$R *.lfm}
 
{ TVecList }
 
function TVecList.AVecCompare(Item1, Item2: Pointer): integer;
begin
  Result := 0;
  if TVector(Item1^)[1] > TVector(Item2^)[1] then begin
    Result := 1;
  end else if TVector(Item1^)[1] < TVector(Item2^)[1] then begin
    Result := -1;
  end;
end;
 
procedure TVecList.Add(v: TVector);
var
  pv: PVector;
begin
  new(pv);
  pv^ := v;
  inherited Add(pv);
end;
 
procedure TVecList.Clear;
var
  i: integer;
  pv: PVector;
begin
  inherited Clear;
  for i := 0 to Count - 1 do begin
    pv := Items[i];
    Dispose(pv);
  end;
  Writeln('VecList.Free');
end;
 
procedure TVecList.Insert(Index: integer; v: TVector);
var
  pv: PVector;
begin
  new(pv);
  pv^ := v;
  inherited Insert(Index, pv);
end;
 
procedure TVecList.Sort;
begin
   inherited Sort(@AVecCompare)// Hier gibts einen Fehler
end;
 
{ TForm1 }
 
procedure TForm1.FormCreate(Sender: TObject);
begin
  VecList := TVecList.Create;
end;
 
procedure TForm1.AddClick(Sender: TObject);
var
  v: TVector;
const
  z: integer = 0;
begin
  Inc(z);
  WriteLn(z);
  v[0] := 0;
  v[1] := z;
  v[2] := 0;
  VecList.Add(v);
end;
 
procedure TForm1.AusgabeClick(Sender: TObject);
var
  v: PVector;
  i: integer;
begin
  for i := 0 to VecList.Count - 1 do begin
    v := VecList.Items[i];
    WriteLn(v^[1]);
  end;
end;
 
procedure TForm1.FormDestroy(Sender: TObject);
begin
  VecList.Free;
  WriteLn('Programm beendet  <Enter>=weiter');
  ReadLn;
end;
 
procedure TForm1.InsertClick(Sender: TObject);
var
  v: TVector;
const
  z: integer = 100;
begin
  Inc(z);
  WriteLn(z);
  v[0] := 100;
  v[1] := z;
  v[2] := 100;
  VecList.Insert(0, v);
end;
 
procedure TForm1.SortClick(Sender: TObject);
begin
  VecList.Sort();
end;
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Benutzeravatar
theo
Beiträge: 10467
Registriert: Mo 11. Sep 2006, 19:01

Re: TList, Vorteil ?

Beitrag von theo »

Steht eigentlich in der Fehlermeldung.

AVecCompare soll eine einfache Funktion sein und keine Methode von TVecLis ("of object").

BeniBela
Beiträge: 308
Registriert: Sa 21. Mär 2009, 17:31
OS, Lazarus, FPC: Linux (Lazarus SVN, FPC 2.4)
CPU-Target: 64 Bit

Re: TList, Vorteil ?

Beitrag von BeniBela »

Mathias hat geschrieben:

Code: Alles auswählen

 
procedure TVecList.Add(v: TVector);
var
  pv: PVector;
begin
  new(pv);
  pv^ := v;
  inherited Add(pv);
end;
 
procedure TVecList.Clear;
var
  i: integer;
  pv: PVector;
begin
  inherited Clear;
  for i := 0 to Count - 1 do begin
    pv := Items[i];
    Dispose(pv);
  end;
  Writeln('VecList.Free');
end;
 
procedure TVecList.Insert(Index: integer; v: TVector);
var
  pv: PVector;
begin
  new(pv);
  pv^ := v;
  inherited Insert(Index, pv);
end;
 


ach, du liebe Güte

Das ist der Hauptnachteil von TList. Bei arrays braucht man nicht für jeden Typ einen Wrapper

Ich denke, man sollte niemals ein Array in die TList stecken

Warf
Beiträge: 1908
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: TList, Vorteil ?

Beitrag von Warf »

Der Vorteil beim Dynamischen Array liegt einfach darin, dass alles als ein Speicherblock behandelt wird.
Der Zugriff auf ein Array Element ist ziemlich intern sehr simpel

Code: Alles auswählen

IntArr[5] = PInteger(DWord(IntArr)+5*SizeOf(Integer))^

während bei Listen ein Eintrag den Verweis auf den Nächsten Eintrag hat List[5] ist also intern

Code: Alles auswählen

Itm := ListHead;
for i:=0 to 5 do
  Itm:=Itm^.Next;
result := Itm^.Value;


Der Vorteil liegt also auf der Hand, Dynamische Arrays verwenden einen Großen Block, den man auch als einen Großen Block behandeln kann (Dieser Block hat eine Feste Länge, kann in einen Stream geschrieben werden, kann mit Move Kopiert werden etc) noch dazu ist der Zugriff auf ein Einzelnes Element recht simpel, da es eine Simple Arithmetische Addition ist. Außerdem benötigen Arrays weniger Speicher, ein Dynamischer array benötigt SizeOf(Pointer) + Length(array)*SizeOf(Typ) Byte, eine Liste benötigt SizeOf(Pointer)+Length(Liste)*(SizeOf(Pointer)+SizeOf(Typ)) Byte.
Bei heutigen PC'S ist dieser Geschwindigkeits und Größenunterschied aber nahezu irrelevant
Listen hingegen können zum einem den Speicher Effizienter nutzen, so wird der Speicherblock auf viele Kleine Speicherblöcke aufgeteilt. Zum Anderen ist das Anhängen und Löschen von Elementen nicht nur einfacher sondern auch schneller. Während bei einem Array der Komplette Speicherblock neu Reserviert werden muss und dann Kopiert werden muss, muss bei einer Liste nur der Speicher für ein Neues element Reserviert werden und dann 2 Werte Fix geändert werden.

Noch da zu gibt es zig Möglichkeiten Listen zu Realisieren (Als Baum, Zyklich, etc)

Antworten