Autor Beitrag
Bergmann89
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1742
Erhaltene Danke: 72

Win7 x64, Ubuntu 11.10
Delphi 7 Personal, Lazarus/FPC 2.2.4, C, C++, C# (Visual Studio 2010), PHP, Java (Netbeans, Eclipse)
BeitragVerfasst: Fr 11.09.09 00:49 
HI,

ich habe folgenden Code:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
  procedure CommaTextToSingleList(CommaText: Stringvar List: TList);
  //CommaText = '0,1;0,2;0,3;'
  var Pos1: Integer;
  var value: PSingle;
  begin
    Pos1 := Pos(';',CommaText);
    while Pos1 <> 0 do
      begin
        new(value);
        value^ := StrToFloat(Copy(CommaText,0,Pos1-1));
        List.Add(value);
        CommaText := copy(CommaText, Pos1+1, Length(CommaText));
        Pos1 := Pos(';',CommaText); 
      end;
  end;


Muss ich den Speicher den die Items benutzen vorher selber mit Dispose freigeben, wenn ich ein Item aus der Liste mit List.del(index) lösche, oder die komplette Liste mit List.clear leere, oder macht das die Liste selbst?
Wenn ich es selbst machen muss, funktioniert das auch mit Records?

MfG & Thx Bergmann.

_________________
Ich weiß nicht viel, lern aber dafür umso schneller^^
Tryer
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 226
Erhaltene Danke: 7



BeitragVerfasst: Fr 11.09.09 05:17 
Ja, den Speicher musst Du selber freigeben. Die Items stehen alle in einem "Array of Pointer" und die Liste kümmert sich nur um dieses Array, nicht aber um die Ziele der Zeiger.

Bei Werten vom Typ Single kannst Du Dir das aber auch sparen, da der Wert mit 4 Byte genauso gross ist wie der Zeiger darauf. Wenn Du es so machst (geht dann nicht für Records) brauchst Du nichts freizugeben (und sparst 50% Speicherplatz).
ausblenden Delphi-Quelltext
1:
2:
3:
4:
var Value: single;
...
List.Add(Pointer(Value)); //eintragen
Value := Single(List.Items[0]); // auslesen


MfG,
Dirk
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19312
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Fr 11.09.09 06:49 
user profile iconBergmann89 hat folgendes geschrieben Zum zitierten Posting springen:
ausblenden Delphi-Quelltext
1:
  procedure CommaTextToSingleList(CommaText: Stringvar List: TList);					
Das ist doppelt gemoppelt. TList ist schon ein Pointer.

Solange du nicht List selbst einen neuen Wert zuweisen willst gehört das var da nicht hin.
Bergmann89 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1742
Erhaltene Danke: 72

Win7 x64, Ubuntu 11.10
Delphi 7 Personal, Lazarus/FPC 2.2.4, C, C++, C# (Visual Studio 2010), PHP, Java (Netbeans, Eclipse)
BeitragVerfasst: Fr 11.09.09 15:02 
Hey,

@Tryer: aber wenn ich mehrere Sachen in die Liste schreiben will und immer List.add(Pointer(Value)) nehm, dann zeigen doch alle Einträge der Liste auf Value und jeder Eintrag hat am Ende den selben Wert, oder? Und mir wurde vor paar Tagen hier im Forum auch gesagt, dass ich das new auf alle Fälle brauch.
Das freigeben vom Record mach ich mit FreeMem, un dann noch den Zeiger auf das record mit Dispose, oder?

@jaenicke: Hast Recht, hab ich grad geändert. Aber wäre es denn so schlimm, wenn das var stehen geblieben wäre?

MfG Bergmann

_________________
Ich weiß nicht viel, lern aber dafür umso schneller^^
Tryer
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 226
Erhaltene Danke: 7



BeitragVerfasst: Fr 11.09.09 15:21 
Nein, es werden nicht alle Pointer auf Value zeigen..
Alle Pointer werden ungültig sein.

Erklärungsversuch:

Das Konstrukt "Pointer(Value)" entspricht nicht "@Value". Es ist kein Zeiger auf Value, sondern die Interpretation des Single-Wertes als Pointer. Im Speicher sind die Strukturen "Pointer" und "Single" gleich gross, darum geht das.

In dem Array wo normalerweise "echte" Pointer stehen, wird einfach der "falsche" Pointer "Value" eingetragen, deer ja gar kein Pointer sondern eine Gleitkommazahl ist.
Der Wert steht jetzt nicht an einer Adresse welche im Array steht, sondern direkt im Array.

New() brauchst Du nur wenn echte Pointer Verwendung finden.

[EDIT]
Zum Freigeben sollte ein Dispose() reichen, FreeMem brauchst Du eigentlich nur nach "GetMem". Wie ist der Record denn aufgebaut ?
[/EDIT]

MfG,
Dirk


Zuletzt bearbeitet von Tryer am Fr 11.09.09 15:38, insgesamt 1-mal bearbeitet
Bergmann89 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1742
Erhaltene Danke: 72

Win7 x64, Ubuntu 11.10
Delphi 7 Personal, Lazarus/FPC 2.2.4, C, C++, C# (Visual Studio 2010), PHP, Java (Netbeans, Eclipse)
BeitragVerfasst: Fr 11.09.09 15:33 
Achso alles klar. Hat klick gemacht ^^
un wie is das jetzt mit den Records?

_________________
Ich weiß nicht viel, lern aber dafür umso schneller^^
Tryer
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 226
Erhaltene Danke: 7



BeitragVerfasst: Fr 11.09.09 15:43 
Zitat:
[EDIT]
Zum Freigeben sollte ein Dispose() reichen, FreeMem brauchst Du eigentlich nur nach "GetMem". Wie ist der Record denn aufgebaut ?
[/EDIT]

Sorry, hab etwas spät editiert.

MfG,
Dirk
HelgeLange
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 735
Erhaltene Danke: 6

Windows 7
Delphi7 - Delphi XE
BeitragVerfasst: Fr 11.09.09 16:54 
Aber um mal generell das Freigeben von Pointern in einer TList zu klären, hier ein Codeschnipsel von mir :)

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
procedure __Free_ImageListInfo(pData : PImageListInfo);
begin
  While pData^.FpData.Count > 0 Do begin
    Dispose(PImageInfo(pData^.FpData.Items[0]));
    pData^.FpData.Delete(0);
  end;  //  --  While pData^.FpData.Count > 0 Do
  Dispose(pData);
end;

begin
  ...
  While FpImageLists.Count > 0 Do begin
    __Free_ImageListInfo(PImageListInfo(FpImageLists.Items[0]));
    FpImageLists.Delete(0);
  end;  //  --  While FpImageLists.Count > 0 Do
  FpImageLists.Free;
  ...
end;


Zur Erklärung : Wenn Du Einträge aus der TList löscht, verringert sich die Anzahl, also Count. Deswegen entweder vom höchsten Element ruterzählen zu 0 oder einfach immer das Element 0 löschen.

Im Bsp. Habe ich eine TList, die Zeiger auf Records enthält, diese records wiederrum beinhalten selbst je eine TList.

_________________
"Ich bin bekannt für meine Ironie. Aber auf den Gedanken, im Hafen von New York eine Freiheitsstatue zu errichten, wäre selbst ich nicht gekommen." - George Bernhard Shaw
Tryer
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 226
Erhaltene Danke: 7



BeitragVerfasst: Fr 11.09.09 17:39 
Autsch, bitte nicht so!

Jedes Delete(0) sorgt dafür das der gesamte Listenteil dahinter um 4 Bytes nach vorne verschoben wird, das ist total überflüssig wenn man wie hier alle Einträge löschen will.
Delete macht nur dann Sinn wenn einzelne Einträge zu löschen sind.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
procedure __Free_ImageListInfo(pData : PImageListInfo);
var
  i: Integer;
begin
  for i := 0 to Pred(pData^.FpData.Count) do
    Dispose(PImageInfo(pData^.FpData.Items[i]));
  pData^.FpData.Free;
end;

var
  p: PImageListInfo;
  i: Integer;
begin
  ...
  for i := 0 to Pred(FpImageLists.Count) do 
  begin
    p := FpImageLists.Items[i];
    __Free_ImageListInfo(p);
    Dispose(p);
  end;
  FpImageLists.Free; // ruft intern Clear() auf, und das dann SetCount(0)
  ...
end;


MfG,
Dirk
Bergmann89 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1742
Erhaltene Danke: 72

Win7 x64, Ubuntu 11.10
Delphi 7 Personal, Lazarus/FPC 2.2.4, C, C++, C# (Visual Studio 2010), PHP, Java (Netbeans, Eclipse)
BeitragVerfasst: Fr 11.09.09 18:22 
Hey,

mein record sieht so aus:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
  THighScoreItem = record
    Name: String;
    Score: Cardinal;
  end;

also wirklich bloß was ganz einfaches.

Delphi-Hilfe hat folgendes geschrieben:
In Delphi erzeugt New eine neue dynamische Variable und gibt einen Zeiger auf den ihr zugewiesenen Speicher zurück. P ist eine Variable eines beliebigen Zeigertyps. Die Größe des reservierten Speicherblocks entspricht der Größe des Datentyps, auf den P zeigt. Auf die neue Variable kann mit P^ Bezug genommen werden. Ist nicht genug Speicher für die dynamische Variable verfügbar, wird eine EOutOfMemory-Exception ausgelöst.

Wenn eine mit New erzeugte dynamische Variable nicht mehr benötigt wird, sollte sie mit der Standardprozedur Dispose wieder freigegeben werden.

Und demnach sollte ja ein normales Dispose reichen, also brauch ich kein FreeMem...

MfG Bergmann

_________________
Ich weiß nicht viel, lern aber dafür umso schneller^^
HelgeLange
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 735
Erhaltene Danke: 6

Windows 7
Delphi7 - Delphi XE
BeitragVerfasst: Sa 12.09.09 00:51 
user profile iconTryer hat folgendes geschrieben Zum zitierten Posting springen:
Autsch, bitte nicht so!

Jedes Delete(0) sorgt dafür das der gesamte Listenteil dahinter um 4 Bytes nach vorne verschoben wird, das ist total überflüssig wenn man wie hier alle Einträge löschen will.
Delete macht nur dann Sinn wenn einzelne Einträge zu löschen sind.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
procedure __Free_ImageListInfo(pData : PImageListInfo);
var
  i: Integer;
begin
  for i := 0 to Pred(pData^.FpData.Count) do
    Dispose(PImageInfo(pData^.FpData.Items[i]));
  pData^.FpData.Free;
end;

var
  p: PImageListInfo;
  i: Integer;
begin
  ...
  for i := 0 to Pred(FpImageLists.Count) do 
  begin
    p := FpImageLists.Items[i];
    __Free_ImageListInfo(p);
    Dispose(p);
  end;
  FpImageLists.Free; // ruft intern Clear() auf, und das dann SetCount(0)
  ...
end;


MfG,
Dirk


Da seh ich ja gleichmal, dass Du einen Bug gefixed hast, der mir ohne das Posten und jetzt lesen garnicht aufgefallen wáre...

Und ja, guter Hinweise mit dem Delete, zum glück habe ich alles zentral und kann es schnell ändern :)

_________________
"Ich bin bekannt für meine Ironie. Aber auf den Gedanken, im Hafen von New York eine Freiheitsstatue zu errichten, wäre selbst ich nicht gekommen." - George Bernhard Shaw
Tryer
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 226
Erhaltene Danke: 7



BeitragVerfasst: Sa 12.09.09 07:41 
user profile iconBergmann89 hat folgendes geschrieben Zum zitierten Posting springen:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
  THighScoreItem = record
    Name: String;
    Score: Cardinal;
  end;

also wirklich bloß was ganz einfaches.

Naja, nicht ganz so einfach.

Dein Record enthält einen "langen String", und der ist etwas schwierig zu behandeln da er genau wie jedes andere dynamisches Array ein Zeiger auf die Stelle ist an welcher die Daten sowie eine Längenangabe und ein Referenzzähler stehen.
Entweder setzt man den String auf '', oder man benutzt die Prozedur Finalize() welche das gleiche macht aber halt allgemeingültig ist und mit allen Datenstrukturen klar kommt.
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
// entweder
PHighScoreItem(Item[i])^.Name := '';
// oder
Finalize(PHighScoreItem(Item[i])^); //nicht Pointer sondern Record übergeben
// und dann
Dispose(PHighScoreItem(Items[i]));

Wichtig (zumindest nach meinem Verständnis) ist das die an Finalize übergebene Struktur oder der an Dispose übergebene Zeiger richtig typisiert sind. Nur so kann die Funktion wissen was alles zu tun ist um den Speicher freizugeben. Da lasse ich mich aber gerne eines besseren belehren. Die OH zum Thema Finalize ist leider etwas schwammig geschrieben, ich halte mich da an die Resultate die mir Memproof liefert.
Im Normalfall wird ein Finalize()-Aufruf sich nie störend auswirken, da er bei Nichtgebrauch einfach wegoptimiert wird. Ein recht einfaches Test ob Finalize() benötigt wird ist also einen Breakpoint auf den Aufruf zu setzen und zu schauen ob dieser aktiv bleibt.

MfG,
Dirk
alzaimar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: Sa 12.09.09 08:41 
@Tryer: Is ja ganz nett, was Du da erzählst, aber total überflüssig. Delphi erledigt das Alles für Dich.

Ein einfaches
ausblenden Delphi-Quelltext
1:
Dispose(p);					

reicht vollkommen.

_________________
Na denn, dann. Bis dann, denn.
Tryer
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 226
Erhaltene Danke: 7



BeitragVerfasst: Sa 12.09.09 08:52 
Ist es dann ein Fehler von Memproof wenn mir dieses erzählt das bei durchgeführtem Dispose noch ein Finalize fehlen würde um den Speicher freizugeben?
alzaimar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: Sa 12.09.09 09:09 
Weiss nicht, habe eben mit FastMM4 geprüft und da war nix... Ich habe es so gemacht:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
Type
  TRecord = Record
    s : String;
    x : Integer;
  End;
  PRecord = ^TRecord;

Var
  P : PRecord;

Begin
  New(P);
  P^.S := 'Some String';
  Dispose(P);
End.

Bisher habe ich FastMM immer vertraut... Was sagt MemProof denn dazu?

Dispose ruft übrigens intern Finalize auf (hab ich mir schon gedacht). Vielleicht hast Du eine ältere Delphi-Version?

_________________
Na denn, dann. Bis dann, denn.
Tryer
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 226
Erhaltene Danke: 7



BeitragVerfasst: Sa 12.09.09 10:35 
Du hast recht, und mir ist wieder was klarer geworden.
Nur wenn man einen Record mit vielen Strings hat (also keinen Zeiger auf den Record sondern MyRec: TMyRecord, dann kann man statt einzeln für alle Strings SetLength(0) bzw :='' aufzurufen auch Finalize() verwenden.

Memproof meckert hier, und da zeigt sich das es halt wichtig ist das der Zeiger typisiert ist:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
Type
  TRecord = Record
    s : String;
    x : Integer;
  End;
  PRecord = ^TRecord;

Var
  P : PRecord;

Begin
  New(P);
  P^.S := 'Some String';
  Dispose(Pointer(P));
End.

Dispose gibt hier nur den Zeiger selber frei, aber kann halt garnicht wissen das da noch ein String hinterlegt ist. Das heißt für das Dispose von TList - Elementen das immer mit "Typisierung" Dispose(PMyRecord(Items[i])); gearbeitet werden muss.

MfG,
Dirk
Bergmann89 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1742
Erhaltene Danke: 72

Win7 x64, Ubuntu 11.10
Delphi 7 Personal, Lazarus/FPC 2.2.4, C, C++, C# (Visual Studio 2010), PHP, Java (Netbeans, Eclipse)
BeitragVerfasst: Sa 12.09.09 12:14 
OK,
dann sind ja alle Fragen beantwortet. Memproof und FastMM4 scheinen ja zeimlich nützliche Tools zu sein, das werd ich mir gleich mal näher ansehen...

MfG Bergmann

_________________
Ich weiß nicht viel, lern aber dafür umso schneller^^
alzaimar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: Sa 12.09.09 12:17 
user profile iconTryer hat folgendes geschrieben Zum zitierten Posting springen:
Memproof meckert hier, und da zeigt sich das es halt wichtig ist das der Zeiger typisiert ist:
:beer: Sehr gut analysiert. Man lernt eben nie aus. Hatte mir nie Gedanken darüber gemacht (weil ich Records selten nutze). Inzwischen muss ich aber hochperformant und mit möglichst geringem Overhead entwickeln, und da ist das sehr nützlich.

_________________
Na denn, dann. Bis dann, denn.