Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Probleme mit Data (Pointer) (https://www.delphipraxis.net/69915-probleme-mit-data-pointer.html)

ranftl 22. Mai 2006 12:15


Probleme mit Data (Pointer)
 
Hallo zusammen!

Ich habe folgendes Problem ich habe ein ListItem, jetzte würde ich gerne in
Data was ja einen Pointer erwartet einen String abspeichern.

Also einfach in OnShow oder so abspeichern und irgendwann im Programm in einer
anderen Funktion wieder rausholen.

Leider jedoch klappt das gar nicht.
Kleiner Code Ausschnitt:

Delphi-Quellcode:
tmp := FieldByName('Test1').AsString + FieldByName('Test2').AsString;
ListItem.Data := Pointer(tmp);
wieder abrufen versuche ich folgendermaßen
Delphi-Quellcode:
tmp := String(ListItem.data);
Wobei tmp in beiden Fällen eine String-Variable ist.
Ich habe auch schon verschiedene Kombination mit den ^ und dem @ operatoren versucht.
Leider bis jetzt ohne Erfolg

Vielleicht könnte mir kurz mal jemand helfen
Danke

lg
ranftl

chaosben 22. Mai 2006 12:22

Re: Probleme mit Data (Pointer)
 
Hi ranftl!

Bei deinem Code existiert der String deiner Wünsche nur so lange, wie du in der Prozedur bleibst, in der dieser Code ausgeführt wird. Probier es lieber mal so (aus dem Kopf):
Delphi-Quellcode:
procedure TuWas;
var
  LText : PString;
begin
  New(LText);
  LText^:=FieldByName('Test1').AsString + FieldByName('Test2').AsString;
  ListItem.Data := Pointer(tmp);
end;

procedure HolDenText;
var
  LText : PString;
begin
  Ltext:=ListItem.Data;
  Self.Caption:=LText^;
end;

//und irgendwann noch den Text freigeben
// Dispose(PString(ListItem.Data));
Und wenn du mal Zeit hast, lies mal 1-2 Tutorials über Pointer. ;)

ranftl 22. Mai 2006 12:31

Re: Probleme mit Data (Pointer)
 
Hallo chaosben!

Danke für deine schnelle Antwort!
Klappt super!

Schönen Tag noch!
ranftl

Chatfix 23. Feb 2007 11:36

Re: Probleme mit Data (Pointer)
 
Muss ich Dispose auch machen wenn ich das ListItem lösche oder ListView.Clear mache oder ist es dann unnötig?
Un sollte nicht auch LText freigegeben werden?

chaosben 23. Feb 2007 16:59

Re: Probleme mit Data (Pointer)
 
Bevor du eine ListView.Clear machst (oder ein Item löschst), musst du natürlich alle Strings freigeben ... und das eben mit dem von dir angeführten Dispose.

Delphi-Quellcode:
Dispose(PString(ListItem.Data));

Chatfix 23. Feb 2007 18:28

Re: Probleme mit Data (Pointer)
 
Also muss ich vor dem Clear sämtliche ListItems durchlaufen?

Was passirt wenn ich das Programm ohne Dispose beende? Wird der Speicher dann freigegeben oder muss ich mich da auch drum kümmern?

Sorry hab noch nich so viel mit Pointern gemacht.

chaosben 24. Feb 2007 11:18

Re: Probleme mit Data (Pointer)
 
Ja, vor dem Clear müsstest du alle Items durchlaufen ... es sei denn, es gibt ein Ereigniss beim Freigeben eines Items (á la VirtualTree).

Und wenn du es nicht tust, sollte eigentlich Memoryleaks übrigbleiben. Am besten kann man das ab BDS4 mit dem Befehl
Delphi-Quellcode:
ReportMemoryLeaksOnShutdown:=true;
testen.

Chatfix 24. Feb 2007 18:07

Re: Probleme mit Data (Pointer)
 
Woher weis ich ob dem Itemw as ich löschen will ein Pointer hinterlegt ist?
Wenns keinen gibt kommt nämlich eine Zugriffsverletzung.

Oder einfach zwischen try except schreiben?

Christian Seehase 24. Feb 2007 18:54

Re: Probleme mit Data (Pointer)
 
Moin Marcel,

bevor Du etwas freigibst, musst Du nur prüfen, ob etwas enthalten ist:

Delphi-Quellcode:
if Assigned(ListItem.Data) then

DGL-luke 24. Feb 2007 18:59

Re: Probleme mit Data (Pointer)
 
... was vorraussetzt, dass der pointer vor allocation / nach disposal ordentlcih genillt wird. Merke: Wilder Pointer gefährlicher als nil-Pointer! ;-)

Chatfix 24. Feb 2007 21:43

Re: Probleme mit Data (Pointer)
 
Und jetzt nochmal für dumme zum mitschreiben bitte :)

Wenn ich vor dem ListView-Clear die Items durchlaufe, was muss ich alles beachten?

Delphi-Quellcode:
if Assigned(ListItem.Data) then
  Dispose(PString(ListItem.Data));
Da nicht unbedingt alle Items einen Pointer erhalten.

Vielen Dank schonmal im Vorraus

DGL-luke 24. Feb 2007 22:18

Re: Probleme mit Data (Pointer)
 
Sollte so hinhauen, ja. Du musst übrigens nicht auf "PString" casten.

btw. was ist "PString"?

chaosben 25. Feb 2007 06:24

Re: Probleme mit Data (Pointer)
 
PString ist ein Pointer auf einen String. :)

Imho sollte man den Pointer so casten, damit Dispose weiß, wieviel es freigeben muss.

DGL-luke 25. Feb 2007 10:04

Re: Probleme mit Data (Pointer)
 
Hmm... das könnte schief gehen. machs lieber so:

Delphi-Quellcode:
type
  PString = ^TStringRec;
  TStringRec = record
    str: string;
  end;
Und dann musst du das noch finalisieren:

Delphi-Quellcode:
if Assigned(ListItem.Data) then
begin
  Finalize(ListItem.Data);
  Dispose(ListItem.Data);
end;
Das Finalisieren ist wichtig, damit Delphi auch den String selbst freigibt. Ein String ist nänmlich eigentlich eine Klasse, und ich hab jetzt nicht genügend Code von dir um zu sehen, ob da alles koscher abläuft.

Du musst übrigens nicht casten, denn wenn du den Speicherbereich per New() alloziiert hast, weiß der MemoryManager, wie viel er an dieser Speicheradresse alloziiert hat. Und Dispose weiß dann auch ohne cast, wie viel freigegeben werden muss.

EDIT: Mooooment mal... ist "PString" schon in Delphi-Systemunits deklariert? Dann sollte die Compilermagic da eh kräftig mitmischen... zeigt mir das doch mal :gruebel:

chaosben 25. Feb 2007 11:19

Re: Probleme mit Data (Pointer)
 
Zitat:

Zitat von DGL-luke
Hmm... das könnte schief gehen.

Eigentlich sollte das nicht schief gehen, denn der Vorteil von New() und Dispose() ist ja gerade der, das diese Routinen (im Gegensatz zu GetMem() und FreeMem()) mit langen Strings umgehen können.

Edit:
Zitat:

Zitat von Die Delphi-Hilfe ©Borland
Finalize sollte nur in Delphi-Quelltext verwendet werden, in dem eine dynamisch erstellte Variable nicht mit der Prozedur Dispose freigegeben wird.

Edit2:
Ok, du hast doch recht. .... nur woher hab ich das mit dem Dispose und den langen Strings ... und außerdem: In der Praxis funktionierts :gruebel:

Muetze1 25. Feb 2007 13:39

Re: Probleme mit Data (Pointer)
 
@DGL-luke: Ein paar Fragen zu deinem letzen Beitrag:

1. Warum ein Record mit nur einem String und nicht direkt Zeiger auf den String? Was soll der Unterschied sein?
2. Das Finalize sollte den Typ bekommen, also PString und nicht einfach nur einen Pointer. Daher bin ich mir nicht sicher, ob Finalize überhaupt in der Form des Aufruf was macht bzw. machen kann. Da ihm der Typ unbekannt ist und er einen untypisierten Zeiger bekommt, kann er nichts ausrichten.
3. Wie du selber schreibst, ist Finalize bei Dispose unnötig. Wenn man nun also das Finalize entfernt, dann sollte Dispose auch den richtigen Zeigertyp bekommen, damit er denn finalisieren kann, sonst fehlt auch ihm das Wissen über den Typ der Struktur. Dieses wird vom Speichermanager nicht abgelegt

DGL-luke 25. Feb 2007 13:47

Re: Probleme mit Data (Pointer)
 
Bevor ich hier noch irgendwas sage, will ich ein Codeschnipsel mit der Deklaration von PString sehen. Hugh.

Christian Seehase 25. Feb 2007 13:57

Re: Probleme mit Data (Pointer)
 
Moin Lukas,

Zitat:

Zitat von DGL-luke
Bevor ich hier noch irgendwas sage, will ich ein Codeschnipsel mit der Deklaration von PString sehen.

Da Du eine Pro-Version hast:
PString in der IDE eingeben, und mit gedrückter STRG-Taste anklicken...

DGL-luke 25. Feb 2007 14:04

Re: Probleme mit Data (Pointer)
 
Ach so ist das also. Na dann is ja klar, dass man sich da nicht drum kümmern braucht(wie ich bereits schrieb). ein einfaches Dispose(PVar) sollte dann reichen, tuts ja auch.

Muetze1 25. Feb 2007 14:56

Re: Probleme mit Data (Pointer)
 
und um nochmal auf meine Ausführungen zurück zu kommen: ein Dispose(PVar), wenn PVar vom richtigen Typ ist. Ein Dispose auf einen untypisierten Pointer bringt nix in Sachen Finalize.

chaosben 25. Feb 2007 15:57

Re: Probleme mit Data (Pointer)
 
Und um alles noch mal zusammen zu fassen:

Dispose() braucht einen typisierten Pointer, damit es weiß, wie viel Speicher es freigeben muss. (Auf Delphisch: Dispose(PString(Datta); )

Enthält der Pointer lange Strings, Variant-Werte oder Interfaces, muss vorher ein Finalize gemacht werden. Vorsorglichg kann man das immer voranstellen, denn ...
Zitat:

Zitat von ... die Delphi-Hilfe ©Borland
Enthält die als Parameter an Finalize übergebene Variable keine langen Strings, Varianten oder Schnittstelle entfernt der Compiler den Aufruf und generiert keinen Code.


Chatfix 25. Feb 2007 22:08

Re: Probleme mit Data (Pointer)
 
Nun bin ich verwirrt?!
Was ist denn nun richtig?
Muss ich unbedingt einen record anlegen um einen einzigen String im ListItem.Data zu hinterlegen?

Über ein Stück Code (nicht mal eben ausm Kopf sondern so richtig durchdacht) vom schreiben ins Data-"Feld" bis hin zum auslesen und dann zum freigeben, würde ich mich sehr freuen. Am betsen alles in verschiedenen Prozeduren.

Vielen Dank im vorraus!

Muetze1 26. Feb 2007 00:36

Re: Probleme mit Data (Pointer)
 
Zitat:

Zitat von chaosben
Dispose() braucht einen typisierten Pointer, damit es weiß, wie viel Speicher es freigeben muss. (Auf Delphisch: Dispose(PString(Datta); )

Sicher? Weil das reine Freigeben des Speichers sollte doch anhand des Pointer so klappen, schliesslich weiss der Speichermanager mit der Pointeradresse, wie gross dieser Block ist. Der Typ sollte doch nur für das Finalize gebraucht werden. :gruebel:

chaosben 26. Feb 2007 05:13

Re: Probleme mit Data (Pointer)
 
Hey Thomas,
du machst mich ja ganz kirre. Weiter oben schreibst du:
Zitat:

Zitat von Muetze1
dann sollte Dispose auch den richtigen Zeigertyp bekommen, damit er denn finalisieren kann, sonst fehlt auch ihm das Wissen über den Typ der Struktur. Dieses wird vom Speichermanager nicht abgelegt

Und hier unten fragst du genau danach. :-D

Aber damit wir das Problem endlich lösen können, werd ich mal sehen, obs irgendwo etwas schriftliches dazu gibt.

Edit:
In der BDS4-Referenz hab ich folgendes gefunden:
Zitat:

Zitat von Borland
Memory manager blocks are always rounded upward to a 4-byte boundary, and always include a 4-byte header in which the size of the block and other status bits are stored. This means that memory manager blocks are always double-word-aligned, which guarantees optimal CPU performance when addressing the block.

Scheinbar braucht man den untypisierten Pointer also nicht casten.

Chatfix 26. Feb 2007 07:12

Re: Probleme mit Data (Pointer)
 
Jetzt weis ich trotzdem noch nicht so recht welche Schritte ich in welcher Reihenfolge ausführen muss :(

Muetze1 26. Feb 2007 08:38

Re: Probleme mit Data (Pointer)
 
Zitat:

Zitat von chaosben
Hey Thomas,
du machst mich ja ganz kirre.

Genau lesen! Ich habe folgendes aus der bisherigen Diskussion von euch gelernt:

1. mit Dispose() freigegebene Dinge braucht man nicht mit Finalize bearbeiten (wurde zuvor behauptet, wurde nicht widersprochen)
2. Finalize() braucht den richtigen Typ um zu arbeiten, damit er die Struktur ordentlich abräumen kann.
3. Dispose() würde mit einem untypisierten Pointer noch immer den Speicher ordentlich freigeben. Er kann dann aber nicht die internen, aktiven Elemente abräumen (Finalize)
4. Dispose() würde mit einem typisierten Pointer ein Finalize (siehe Punkt 1) mit enthalten und dann den Speicher freigeben.

Somit, habe ich mit der Frage zuvor folgendes klären wollen: Wenn man das Finalize() vor dem Dispose selbst aufruft (Finalize braucht immer den genauen Typ), dann kann man Dispose() mit einem untypisierten Pointer aufrufen. Denn: den typisierten Pointer braucht Dispose() nur, wenn man vorher kein Finalize() gemacht hat, und somit Dispose() dies mit macht. Diese Behauptung stützt sich auf den 1. Punkt.

Ich habe in der vorherigen Frage nur noch mal nachgehakt, da Dispose() den alloziierten Speicherbereich immer freigeben kann - dafür braucht er keinen typisierten Pointer. Das wollte ich nochmal genau nachfragen. Wenn man das Finalize() aber Dispose() mit überlassen will, dann muss der richtige Typ beim Aufruf angegeben werden.

Dispose() hat als Gegenstück zu New() augenscheinlich nur die Hauptaufgabe Speicher zu alloziieren und zu dealloziieren. New() braucht dabei immer einen Typ, da er sich daraus die Grösse des alloziierenden Speichers ableitet. Dispose() braucht sich diese Grösse nicht mehr neu abzuleiten aus dem Typ, da sie vom Speichermanager hinterlegt wurde bei der Alloziierung. New() macht grundsätzlich ein Initialize(), wenn solche o.g. aktiven Typen enthalten sind. Dispose kümmert sich vor dem freigeben entsprechend um das Finalize() - und genau dafür braucht er den Typ - für das reine freigeben des alloziierten Speichers nicht.

Initialize() und Finalize() werden benötigt, wenn man aktive Typen in z.B. einer Struktur hat, welche nicht mit den intelligenten Funktionen New()/Dispose() verwaltet werden, sondern z.B. über AllocMem(), GetMem(), etc und deren Gegenstücke.

Jetzt klarer? Bzw. kannst du mir nun nochmal bitte meine Frage vom Beitrag zuvor entweder bestätigr oder entsprechend korrigieren?

chaosben 26. Feb 2007 09:10

Re: Probleme mit Data (Pointer)
 
So, ich komme nach einem weiteren Studium der Hilfe zu folgendem Schluss:
  • New() und Dispose() gehören zu einer Gruppe und Initialize(), Finalize, GetMem() und FreeMem() bilden die andere Gruppe. Man sollte die beiden Gruppen imho nicht mischen.
  • New() ersetzt die Kombination aus GetMem() und Initialize() - Dispose() ersetzt Finalize() und FreeMem().
  • Dispose() braucht keinen typisierten Pointer. (weil: siehe oben)

Ist jetzt damit alles geklärt?

PS: Sorry, wenn ich nicht richtig gelesen habe. :)

Muetze1 26. Feb 2007 10:49

Re: Probleme mit Data (Pointer)
 
Zitat:

Zitat von chaosben
PS: Sorry, wenn ich nicht richtig gelesen habe. :)

Kein Problem, Hauptsache wir bekommen es richtig hin, und es steht was richtiges für die Nachwelt hier im Forum.

Zitat:

Zitat von chaosben
Ist jetzt damit alles geklärt?

Nein, leider nicht. Und zwar zu dieser Aussage:

Zitat:

Zitat von chaosben
  • Dispose() braucht keinen typisierten Pointer. (weil: siehe oben)

Ich bin zuvor ja zu dem Schluss gekommen, dass New() und Dispose() ein Intialize() und Finalize() übernehmen/mitmachen und somit müsste Dispose() einen typisierten Pointer bekommen, damit er dieses Finalize machen kann. Dispose() kenn mit der Adresse die Grösse, aber nicht den Typ.

chaosben 26. Feb 2007 11:40

Re: Probleme mit Data (Pointer)
 
Liste der Anhänge anzeigen (Anzahl: 1)
Ich glaub jetzt hab ichs:
  • Das was ich oben über die 2 Gruppen geschrieben habe ist falsch. Dispose kapselt nämlich Finalize und FreeMem.
    Delphi-Quellcode:
    procedure _Dispose(p: Pointer; typeInfo: Pointer);
    begin
      _Finalize(p, typeinfo);
      FreeMem(p);
    end;
  • Der Praxistest hat gezeigt: Man muss an Dispose einen typisierten Pointer übergeben.

@Chatfix: Du bekommst deine Antwort noch. Einen kleinen Moment bitte. :)

Muetze1 26. Feb 2007 12:10

Re: Probleme mit Data (Pointer)
 
So, genau. Somit bin ich auch zufrieden, weil genau das war mein Wissensstand und somit bin ich froh, dass es richtig ist. Danke für's klären...

Chatfix 26. Feb 2007 13:30

Re: Probleme mit Data (Pointer)
 
Vielen Dank chaosben!
Scheint wunderbar zu klappen :)


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