![]() |
TObjectlist.add(record)?
Hallo zusammen,
ich möchte zu einer TOjectlist ein Record hinzufügen und bekomme immer einen Typenkonverierungsfehler.
Delphi-Quellcode:
Wie kann ich das Problem umgehen?
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; |
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 |
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 |
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. |
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; |
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: |
Re: TObjectlist.add(record)?
Zitat:
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 |
Re: TObjectlist.add(record)?
Zitat:
Zitat:
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; |
Re: TObjectlist.add(record)?
Zitat:
|
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 |
Re: TObjectlist.add(record)?
Zitat:
Mal sehen ob ich's erlären kann :) Wir haben hier eine völlig sinnlose Function mit einer Lokalen variablen.
Delphi-Quellcode:
Nun ist i eine lokale Variable, die nur für die Function benötigt wird. Während die Procedure durchläuft ist i auf einer bestimmten Stelle im Hauptspeicher zugreifbar. Das heist ein Bestimmter Speicherplatz im Hauptspeicher ist für i reserviert. Was passiert nun mit i nachdem die Procedure durchgelaufen ist?
Function VoelligSinnloseBerechnung(x:integer):integer;
var i:integer; begin i:=x*3; result:=i*5; end; [ ] 1: Die Variable behält ihren Speicherplatz. Somit würde die Sache mit dem Pointer/Zeiger, der von marabu vorgeschlagen wurde funktionieren. [ ] 2: Der Speicherbereich wird freigegeben und eine andere Procedure könnte dort an diesem Speicherplatz die nächste Variable plazieren. Stell dir vor diese Function wird im Laufe des Programms ca. 3 Millionen mal aufgerufen. Mit der ersten Variante sähe das ganz schön schlimm aus. Denn für jeden Aufruf würde i einen neuen Speicherpaltz erhalten und auch behalten. Aber nur mit dieser Variante würde würde das Beispiel von Marabu funktionieren, denn der Zeiger der in die Liste aufgenommen wird, zeigt eben auf diesen immer gültigen Speicherbereich. Korrekt ist aber die zweite Version. Mit dieser Version kannst du dann aber nicht mehr mit Zeigern auf die lokalte Variable i arbeiten. Denn nach Beenden der Procedure zeigt der Zeiger auf einen Speicherbereich, der vieleicht noch den Wert von i beinhaltet aber ggf. auch schon wieder für andere Zwecke verwendet wird. Edit: Tja. Da war Marabu wohl schneller. (Und hat es auch eleganter erklärt) @Marabu: Wollte dich nicht kränken :) |
Re: TObjectlist.add(record)?
@bernau, @marabu:
Die ganze Sache ist ein grosses Missverständniss. Die Sache mit den Local/Global variablen, Stack/Heap ist mit komplett klar, nur wollte ich mit meiner letzen Frage deine, brenau - von mir missverstandene Aussage, nochmals klären. Alles kann man an dieser Stelle ruhig vergessen, was meine lezte Frage und darauf gefolgte Antworten, betrifft. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:44 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz