Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi TObjectlist.add(record)? (https://www.delphipraxis.net/64667-tobjectlist-add-record.html)

ozz 6. Mär 2006 20:05


TObjectlist.add(record)?
 
Hallo zusammen,
ich möchte zu einer TOjectlist ein Record hinzufügen und bekomme immer einen Typenkonverierungsfehler.
Delphi-Quellcode:
type TCLCategory = record
     id:integer;
     Category:string;
     parent:integer;
end;


type TMyClass = class (TComponent)
private
 FCategory: TObjectList;
 ....
 
procedure TMyClass.irgendetwas;
var current:TCLCategory;
begin
 ....
 FCategory.Add(Current); <-hier
...
end;
Wie kann ich das Problem umgehen?

marabu 6. Mär 2006 20:13

Re: TObjectlist.add(record)?
 
Hallo.

Um Records zu verwalten solltest du nicht TObjectList nehmen. Nimm TList und beachte, dass du einen Zeiger (@Current) übergeben musst.

Grüße vom marabu

bernau 6. Mär 2006 20:49

Re: TObjectlist.add(record)?
 
Gaaaannnz schlimm. :shock:


current ist eine lokale Variable! Diese ist nach verlassen der Procedure nicht mehr gültig.

Du kanst nicht mit Records in Listen arbeiten. Da must du schon ein Object draus machen und artig instanzieren. Freigeben nicht vergessen. Aber da kann dir TObjectList mit ownsobjects=true helfen.


Gerd

ozz 6. Mär 2006 21:45

Re: TObjectlist.add(record)?
 
Danke Marabu!
Ich habe es mit jetzt TList gemacht.Nur der Vollständigkeit, wie wäre es mit TObjectlist, auch wenn es nicht sauber ist?

Danke!

@bernau
Danke für den Tipp.Hast du dazu ein Code-Snippet? Irgendwie stehe ich auf dem Schlauch.

sniper_w 6. Mär 2006 22:44

Re: TObjectlist.add(record)?
 
Mit record kann man sehr wohl arbeiten, genauer gesagt mit den Pointers auf Record.
Delphi-Quellcode:
type
  TForm1 = class(TForm)
    Button1: TButton;
    ListBox1: TListBox;
    procedure Button1Click(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    List:TList;
    procedure AddItem( NewItem:pointer);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

type
  PmyRec = ^TmyRec;
  TmyRec = record
    item1:Integer;
    item2:Byte;
    item3:string; // vorsicht ;)
  end;

procedure TForm1.AddItem(NewItem: pointer);
begin
  with PmyRec( NewItem )^ do
  begin
    ListBox1.Items.Add( IntToStr( item1 ));
    ListBox1.Items.Add( IntToStr( item2 ));
    ListBox1.Items.Add(  item3 );
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  newRec : PmyRec;
  i:Integer;
begin
  Randomize();

  if not Assigned(List) then
  begin
    List := TList.Create;
  end;

  for i:=0 to 10 do
  begin

    New( newRec );

    with newRec^ do
    begin
      item1 := random(100);
      item2 := random(255);
      item3 := 'hallo';
    end;

    List.Add( newRec );
    AddItem( newRec );
  end;
end;

procedure TForm1.FormDestroy(Sender: TObject);
var
  i:Integer;
  rec:PmyRec;
begin
  for i:= List.Count-1 downto 0 do
  begin
    rec := PmyRec ( List.Items[i] );
    rec^.item3 := '';
    List.Delete(i);
    Dispose(rec);
  end;

  List.Free();
end;

ozz 7. Mär 2006 05:46

Re: TObjectlist.add(record)?
 
Guten Morgen sniper_w!
Danke für dein sehr ausfühliches Beispiel. Ich habe es etwas anders gemacht, aber ich lerne immer gern dazu. :idea:

bernau 7. Mär 2006 08:09

Re: TObjectlist.add(record)?
 
Zitat:

Zitat von sniper_w
Mit record kann man sehr wohl arbeiten, genauer gesagt mit den Pointers auf Record.

ACK. So gehts natürlich, da du mit "New" bzw "Dispose" den Speicher reservierst und auch wieder freigibst.

Marabu hat sich in seinem Beispiel aber auf die Variable "current" bezogen. Dies ist eine lokale Variable in der Procedure, die nach Beendigung der Procedure schlicht nicht mehr vorhanden ist und somit der Zeiger ins Nirvana zeigt. Dumm ist, daß die Belegung des Speichers (da wo der Pointer hinzeigt) tatsächlich noch eine Zeit lang so ist wie Sie sein sollte. Aber irgendwann wird dieser Speicherbereich von anderen Daten überschrieben. Darauf wollte ich nur aufmerksam machen, bevor stundenlang nach Fehlern gesucht wird.

Übrigens finde ich es eleganter mit Objekten zu arbeiten statt mit Pointern auf Records. Aber das ist reine Geschmackssache.

Gerd

bernau 7. Mär 2006 08:19

Re: TObjectlist.add(record)?
 
Zitat:

Zitat von ozz
Ich habe es mit jetzt TList gemacht.Nur der Vollständigkeit, wie wäre es mit TObjectlist, auch wenn es nicht sauber ist?

TList und TObjectlist unterscheiden sich nicht besonders. Im Gegensatz zu TList kannst du aber bei TObjectlist mit dem Property ownsobjects angeben, daß TObjectlist die zugefügten Objekte wieder freigibt, wenn die einzelnen Elemente entfernt werden bzw. die glanze Liste freigegeben wird.


Zitat:

Zitat von ozz
Danke für den Tipp.Hast du dazu ein Code-Snippet? Irgendwie stehe ich auf dem Schlauch.


Hier mal eben schnell zusamengeschrieben:


Delphi-Quellcode:
type TCLCategory = class (TObject) // <- kein record sondern ein Object
     id:integer;
     Category:string;
     parent:integer;
end;


type TMyClass = class (TComponent)
private
FCategory: TObjectList;
....


procedure TMyClass.create;
begin
FCategory:=TObjectList.create;
FCategory.ownsobjects:=true;
end;

....

procedure TMyClass.irgendetwas;
var
  current:TCLCategory;
begin
....
current:=TCLCategory.create;

// Hier die Were zuweisen
current.Category:='Irgendein String';


FCategory.Add(Current);
...
end;

sniper_w 7. Mär 2006 14:31

Re: TObjectlist.add(record)?
 
Zitat:

Zitat von bernau
Aber irgendwann wird dieser Speicherbereich von anderen Daten überschrieben. Darauf wollte ich nur aufmerksam machen, bevor stundenlang nach Fehlern gesucht wird.

Kannst du das bitte mehr dazu sagen. :shock:

marabu 7. Mär 2006 16:00

Re: TObjectlist.add(record)?
 
Hallo Leute,

mein Beitrag #2 war wohl Auslöser für eine heiße Diskussion ganz nach dem Vorbild Shakespeare's Much Ado about Nothing: Der Klammerzusatz (@Current) war nur ein missglückter Versuch meinen allgemein gehaltenen Beitrag doch noch etwas in Bezug zum Code von ozz zu setzen. Wer mir zutraut, ich würde die Adresse einer Variablen auf dem Stack mit der Adresse einer Variablen auf dem Heap verwechseln, der kränkt mich. Aber Gerd hat sicherlich recht mit seinem Hinweis - wer weiß wen ich sonst noch alles ungewollt aufs Glatteis schicke.

Der Speicher für lokale Variablen einer Funktion oder Prozedur wird vor dem Aufruf des Codes durch Verschieben des stack pointers bereit gestellt. Nach der Rückkehr aus der Funktion wird dieser Speicher wieder zur Verfügung gestellt. Bei erneutem Aufruf der Funktion kurz danach kann es passieren, dass man auf die alten Inhalte zugreifen kann. Generell wird dieser Speicherbereich aber bei Bedarf wieder von anderen Routinen verwendet. Will ich selbst die Lebensdauer des Speichers bestimmen, dann muss ich den Speicher entweder über globale Variablen bereit stellen oder ich verwalte den Speicher über die entsprechenden Funktionen auf dem Heap.

@sniper_w: eigentlich war ich davon überzeugt, dass dein Code-Beispiel die Dinge bereits ausreichend beleuchtet hatte, aber dein letzter Beitrag hat mich dann doch noch zu einem beherzten Griff in die Tasten bewogen.

Freundliche Grüße vom marabu


Alle Zeitangaben in WEZ +1. Es ist jetzt 02:49 Uhr.
Seite 1 von 2  1 2      

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