Autor |
Beitrag |
Xion
      

Beiträge: 1952
Erhaltene Danke: 128
Windows XP
Delphi (2005, SmartInspect), SQL, Lua, Java (Eclipse), C++ (Visual Studio 2010, Qt Creator), Python (Blender), Prolog (SWIProlog), Haskell (ghci)
|
Verfasst: Di 12.02.13 20:37
Hi,
wenn ich ein Record anlege, wird es standardmäßig freigeben. Z.B:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9:
| type TInt=record i: integer; end; procedure DoSomething; var R: TIntRec; begin R.i:=50; end; |
Wenn ich das Record als Rückgabewert verwende, dann wird es (vorerst) nicht freigegeben.
Delphi-Quelltext 1: 2: 3: 4:
| function DoSomething: TIntRec; begin Result.i:=50; end; |
Jetzt zur Frage:
Was passiert mit dem Record, wenn ich einen Pointer darauf z.B. in eine Liste einfüge:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8:
| var List: TList;
procedure DoSomething; var R: TIntRec; begin R.i:=50; List.Add(@R); end; |
Wann wird es nun freigegeben? Hoffentlich nicht beim Verlassen der Prozedur, sonst ist der Pointer in der Liste ja ungültig. Lösche ich nun den Pointer mit List.Delete(0), dann sollte das Record möglichst freigegeben werden, da ja nun kein Pointer mehr darauf existiert. Ist dies der Fall? Wenn ja, führt Delphi ein Reference Counting um zu bemerken, wenn kein Pointer mehr auf das Record zeigt? Das wäre in diesem Fall dann ziemlich Speicheraufwändig, da ich den Counter für jeden Integer benötige (also 50% overhead).
Unterm Strich die Frage:
Wenn ich das Record wie oben in die Liste einfüge, muss ich mir dann irgendwelche Sorgen um den Speicher machen? Ich habe lediglich Themen dazu gefunden, bei denen ein Pointer darauf mit New() angelegt wurde, der dann natürlich mit Dispose wieder freigegeben werden musste.
Habe dazu leider keine Antwort im Netz gefunden. Meine Tests vermitteln den Eindruck, dass Delphi es genau so macht wie ich es haben will (wie eigentlich immer, genau invers zu C++  ).
Danke für die Antworten Moderiert von Narses: Topic aus Sonstiges (Delphi) verschoben am Mi 13.02.2013 um 00:03
_________________ a broken heart is like a broken window - it'll never heal
In einem gut regierten Land ist Armut eine Schande, in einem schlecht regierten Reichtum. (Konfuzius)
|
|
WasWeißDennIch
      
Beiträge: 653
Erhaltene Danke: 160
|
Verfasst: Di 12.02.13 20:46
Nach meiner Kenntnis wird der Record wie alle lokalen Nicht-Pointer-Variablen nach Verlassen der Routine ungültig. Deshalb sollte man das wohl eher so schreiben:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9:
| var List: TList;
procedure DoSomething; var R: PIntRec; begin New(R); R^.i:=50; List.Add(R); end; |
[edit] Oder anders ausgedrückt: AFAIK landen lokale Variablen auf dem Stack und werden nach Verlassen der enthaltenden Routine ungültig. Das betrifft in meinem Beispiel auch R, d.h. der Pointer R ist flüchtig, nicht aber die dahinterstehenden Daten. Durch das Hinzufügen zur Liste hingegen wird er dann auf dem Heap abgelegt und ist somit verfügbar. Genaugenommen ist das dann aber nicht mehr der "Original-R", sondern eine Kopie davon. [/edit]
Für diesen Beitrag haben gedankt: Martok, Xion
|
|
Xion 
      

Beiträge: 1952
Erhaltene Danke: 128
Windows XP
Delphi (2005, SmartInspect), SQL, Lua, Java (Eclipse), C++ (Visual Studio 2010, Qt Creator), Python (Blender), Prolog (SWIProlog), Haskell (ghci)
|
Verfasst: Di 12.02.13 21:30
WasWeißDennIch hat folgendes geschrieben : | Oder anders ausgedrückt: AFAIK landen lokale Variablen auf dem Stack und werden nach Verlassen der enthaltenden Routine ungültig |
Ah, ok, alles klar. Und wenn ich das Record als Rückgabewert zurückgebe, dann bleibt es vorerst auf dem Stack, bis es dann später vom Stack fliegt, wenn die aufrufende Prozedur endet?
_________________ a broken heart is like a broken window - it'll never heal
In einem gut regierten Land ist Armut eine Schande, in einem schlecht regierten Reichtum. (Konfuzius)
|
|
GuaAck
      
Beiträge: 378
Erhaltene Danke: 32
Windows 8.1
Delphi 10.4 Comm. Edition
|
Verfasst: Di 12.02.13 22:25
... oder Du eine andere FUNCTION oder PROCEDURE aufrufst, die den Stack überschreibt, also alles mehr oder weniger Zufall. Also entweder per NEW oder in einer übergordneten Variable. Übrigens: Wenn im Compiler die entsprechenden Warnungen aktiviert sind, dann sollte die Warnung "unsicher Code @Operator" kommen, genau aus den angeführten Gründen.
Gruß
GuaAck
|
|
Xion 
      

Beiträge: 1952
Erhaltene Danke: 128
Windows XP
Delphi (2005, SmartInspect), SQL, Lua, Java (Eclipse), C++ (Visual Studio 2010, Qt Creator), Python (Blender), Prolog (SWIProlog), Haskell (ghci)
|
Verfasst: Mi 13.02.13 20:30
GuaAck hat folgendes geschrieben : | Also entweder per NEW oder in einer übergordneten Variable. |
Das gilt, wenn ich einen Pointer zurück gebe, oder? Wenn ich das Record selbst zurück gebe, dann wird eine Kopie zurückgegeben. Genau wie bei Integer. Oder etwa nicht?
Also mein neues Wissen mal angewendet:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37:
| type TRec=record i: integer; end;
function Generate: TRec; begin Result.i:=25; end;
procedure Insert; var R: TRec; iP: ^Integer; begin R:=Generate; new(iP); iP^:=R.i; List.Add(iP); end;
procedure Delete; var iP: ^Integer; begin iP:=List.First; List.Delete(0); Dispose(iP); end;
procedure Main; begin List:=TList.Create;
Insert; Delete;
List.Free; end; |
Ok so, oder?
PS:
Hab jetzt die enstprechende Compiler-Warnung gefunden und aktiviert. Bei obigem Code sagt er:
[Warnung] (Zeile 17) W1047 Unsicherer Code '^-Operator'
Die Warnung kommt auch, wenn ich direkt Schreibe: iP^:=25;. Vorschläge?
FastMM4 findet zumindest keine Speicherleaks, also das ist ok.
Edit2:
Ich habe mehrfach gelesen, dass die Warnung lediglich was damit zu tun hat, das man mit .Net ^ und @ usw. nicht mehr benutzen kann. "sicher" bezieht sich daher eher auf "deprecated". Ich frage mich, wie ich eine generische Datenstruktur dann überhaupt machen soll, ohne Pointer  Delphi 2005 kennt ja noch keine Generics. Für alles Klassen? Bäh!
_________________ a broken heart is like a broken window - it'll never heal
In einem gut regierten Land ist Armut eine Schande, in einem schlecht regierten Reichtum. (Konfuzius)
|
|
|