AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Algorithmen, Datenstrukturen und Klassendesign Delphi vergisst die Werte der Eigenschaften meiner Klasse
Thema durchsuchen
Ansicht
Themen-Optionen

Delphi vergisst die Werte der Eigenschaften meiner Klasse

Ein Thema von Andre93 · begonnen am 25. Aug 2011 · letzter Beitrag vom 19. Sep 2011
Antwort Antwort
Seite 2 von 2     12   
Andre93

Registriert seit: 10. Jun 2010
15 Beiträge
 
Delphi 6 Personal
 
#11

AW: Delphi vergisst die Werte der Eigenschaften meiner Klasse

  Alt 31. Aug 2011, 23:48
hey,
sry hatte vergesse das mit der delphi version anzugeben.
also ich hab delphi 6, weil wir in der schule auch nichts neueres haben, naja auf jeden fall dürfte bei delphi 6 ja nicht der fehler auftreten von dem du redest..
ich hab das jetzt mal mit setlength gemacht und es funktioniert eigentlich auch alles. das einzig komische ist nur, dass nachdem ich mit meinem output fertig bin enthält mein "rückgabe-array" zwar die richtigen werte, wenn ich dann allerdings mit einer zählschleife das array durchakkern will um die inhalte wieder auszugeben ist der inhalt des array mit einmal nicht mehr arB : [69,100,105,116,49,...,...] sondern nur noch zuerst arB : (69), dann arB : (36), dann arB : (). wenn man sich das ganze in der watchlist anguckt sieht es auf jeden fall nachdem moment wo die schleife beginnt nich mehr wie ein array aus.

hier mein quelltext :

das hier funktioniert noch :
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
begin
 D := TData.Create;
 D.Init(500,1);
end;

procedure TForm1.Button2Click(Sender: TObject);
var
 arB : array of Byte;
 I,Len : Integer;
begin
 len := length(Edit1.Text);
 SetLength(arB,len);
 for I := 0 to len - 1 do
  arB[I] := ord(Edit1.Text[I+1]);
 D.Input(@arB,len);
end;
und bei dem hier hat er bis vor der schleife noch die richtigen werte im array und während der schleife läuft dann irgendwas schief :

Delphi-Quellcode:
procedure TForm1.Button3Click(Sender: TObject);
var
 P : pointer;
 arB : TArByte;
 I : Integer;
begin
 D.OutPut(P);
 SetLength(arB,D._RealSize);
 arB := TArByte(P^); //bis hier ist alles wie es sein soll
 for I := 0 to D._RealSize - 1 do
  Caption := Caption + chr(arB[I]);
end;
schönen abend noch..
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.071 Beiträge
 
Delphi 12 Athens
 
#12

AW: Delphi vergisst die Werte der Eigenschaften meiner Klasse

  Alt 1. Sep 2011, 00:54
Wie zu erwarten war ... überall Speicherlecks.
Aber erstmal egal


D.Input(@arB,len);
@arB = ein Zeiger auf die Variable
@arB[0] = ein Zeiger auf die Daten
Denn ein dynamisches Array ist intern ein Zeiger und die Daten stecken nicht direkt in der Variable.
Bei einem statischen Array entspicht @arB zwar einem @arB[Low(arB)], aber besser immer mit Index ... nicht daß man es mal vergißt und es dann bei einem Dynamischen knallt.


bis hier ist alles wie es sein soll
falsch gedacht

Delphi-Quellcode:
 D.OutPut(P);
 SetLength(arB,D._RealSize);
 arB := TArByte(P^); //bis hier ist alles wie es sein soll
P gibt einen Speicherbereich (Pointer) zurück
arB ist aber kein billiger Zeiger (Delphi-Referenz durchsuchenPointer), sondern ein array of byte

Dann reservierst du Speicher für das dyn. array (SetLength),
welchen du dann wieder verwirfst (:= ) und versuchst den Pointer als array of byte zu interpretieren,
was natürlich niemals funktionieren kann, da es vollkommen unterschiedliche Typen sind und sie ihren speicher unterschiedlich verwalten.

Du mußt also den speicher von P in das Array kopieren.
Praktisch so ähnlich, wie du schonmal den Text in das Array reinkopiert hast. (Edit1.Text ist der Inhalt von P)
Delphi-Quellcode:
 for I := 0 to len - 1 do
  arB[I] := ord(Edit1.Text[I+1]);
(statt solcher Schleifen kann man natürlich auch Delphi-Referenz durchsuchenMove verwenden)

P köntest du dir dafür nach PStaticBytes casten.
Delphi-Quellcode:
type
  TStaticBytes = array[0..0] of Byte;
  PStaticBytes = ^TStaticBytes;
PS: 0..0 ist ein sonderfall, denn dort macht Delphi niemals eine Bereichsprüfung für den Index.
Man könnte auch [0..666] nehmen (666 = irgendein Wert, welcher groß genug ist ... also mindestens so groß, wie der maximal zu erwartende Indexwert ... da ist [0..0] natürlich einfacher )



Und am Ende vergißt du auch noch P wieder freizugeben, welches in OutPut reserviert wurde.
Darum macht man sowas eigentlich auch besser nicht ... Speicher sollte möglichst immer in der Ebene freigeben werden, wo er reserviert wurde.

Mach Output genauso wie input (Pointer+Len) und laß' die Daten vom Output direkt in @arB[0] reinschreiben.
(Len ist dann die Länge von arB, also die maximale Größe der daten, welche in arb reinpassen würde, was man in Output prüfen sollte, bevor man was reinschreibt)








Delphi-Quellcode:
TBytes = array of Byte; // in neueren Delphis kann man das dann weglassen, da es diesen Typ dort schon gibt

TDataType = (dtNone, dtBool, dtByte, dtChar, dtString, dtInteger, dtReal); // ein Enumerator

TData = class
 private
  _Data : Pointer;
  _MaxSize, _RealSize: Integer;
  _DataType : TDataType;
 public
  procedure Init(MaxSize : Integer; DataType : TDataType); // wäre als Constructor bestimmt besser geeignet
  destructor Destroy; override;

  procedure Input(Data : Pointer; DataSize : Integer);

  property MaxSize: Integer read _MaxSize;
  property RealSize: Integer read _RealSize;
  property DataType: TDataType read _DataType;
  procedure Output(Data : Pointer; MaxSize: Integer);
 end;

implementation

procedure TData.Init(MaxSize, DataType : Integer);
begin
 _MaxSize := MaxSize;
 _DataType := DataType;
 GetMem(_Data, _MaxSize);
end;

destructor TData.Destroy;
begin
 FreeMem(_Data);
end;

procedure TData.Input(Data : Pointer; DataSize : Integer);
begin
 if RealSize <= _MaxSize then
  begin
   _RealSize := DataSize;
   Move(Data, _Data, DataSize);
  end
 else
  ShowMessage('Speicherplatz überschritten!');
end;

procedure TData.Output(Data : Pointer; MaxSize: Integer);
begin
 if MaxSize >= _RealSize then
  Move(_Data, Data, _RealSize)
 else
  ShowMessage('Data zu klein!');
end;
Zitat:
Delphi-Quellcode:
D := TData.Create;
D.Init(500,1);
Mit Init als Constructor, würde dann D := TData.Create(500, 1); gehn.

Delphi-Quellcode:
procedure TForm1.Button2Click(Sender: TObject);
var
 arB : array of Byte;
 I,Len : Integer;
begin
 len := length(Edit1.Text);
 SetLength(arB, len);
 for I := 0 to len - 1 do
  arB[I] := ord(Edit1.Text[I+1]);
 D.Input(@arB[0], len);
end;

procedure TForm1.Button3Click(Sender: TObject);
var
 arB : TArByte;
 I : Integer;
begin
 SetLength(arB, D.RealSize); // D._RealSize ist PRIVAT ... sowas verwendet man nicht extern
 D.OutPut(@arB[0], Length(arB));
 for I := 0 to High(arB) do
  Caption := Caption + chr(arB[I]);
end;

Enumeratoren sind toll, erstmal ist somit alles logisch und physisch zusammen, was zusammen gehört
und die Quelltextvervollständigung verrät einem was man an soeine Variable/Parameter übergeben kann, da der Compiler nun auch weiß was zusammengehört.
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.

Geändert von himitsu ( 1. Sep 2011 um 01:25 Uhr)
  Mit Zitat antworten Zitat
Andre93

Registriert seit: 10. Jun 2010
15 Beiträge
 
Delphi 6 Personal
 
#13

AW: Delphi vergisst die Werte der Eigenschaften meiner Klasse

  Alt 2. Sep 2011, 00:16
hey, danke dass ihr euch alle so viel mühe macht vorallem aber danke an himitsu. ihr helft mir alle wirklich ganz schön.

@himitsu,
das was du geschrieben hast leuchtet mir mittlerweile ein und ich verstehe jetzt auch warum meins falsch war..
was ich bloß noch mal fragen wollte ist :
ich dachte mir eigentlich es währe praktischer den speicher _data wirklich erst dann zu reservieren wenn man ihn braucht, also somit beim input. du hast den getmem()-befehl allerdings schon gleich bei init mit aufgerufen.
Delphi-Quellcode:
procedure TData.Init(MaxSize, DataType : Integer);
begin
 _MaxSize := MaxSize;
 _DataType := DataType;
 GetMem(_Data, _MaxSize); //das hier meine ich
end;
währe es nicht effizienter das im input zu machen? oder macht das so wie so keinen sinn und ist auch so wie so nicht umsetzbar??

außerdem wollte ich fragen ob du deinen änderungen am quelltext schon einmal getestet hast, denn ich hab damit das problem, dass nach dem output das array nicht die gesuchten werte sondern arB : [0,0,0,0,0] enthält.
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.071 Beiträge
 
Delphi 12 Athens
 
#14

AW: Delphi vergisst die Werte der Eigenschaften meiner Klasse

  Alt 2. Sep 2011, 00:29
Wäre auch möglich, aber dann mußt du auch im Input prüfen, ob schon Speicher reserviert wurde, diesen Freigeben und kannst danach neuen Speicher reservieren.

PS: statt dem Pointer + RealSize könnte man intern ebenfalls ein array of Byte verwenden, dann kümmert sich Delphi um die Speicherverwaltung und abgesehn von dem SetLength in Input muß man sich um nichts mehr kümmern.

Es wird nichmal mehr viel mehr Speicher benötigt.
- die Array-Daten sind 8 Byte (Length + RefCount) größer und dafür Spart man 4 Byte (RealSize aka Length) in seiner Klasse ein (bei 32 Bit-Apps)
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.
  Mit Zitat antworten Zitat
Andre93

Registriert seit: 10. Jun 2010
15 Beiträge
 
Delphi 6 Personal
 
#15

AW: Delphi vergisst die Werte der Eigenschaften meiner Klasse

  Alt 6. Sep 2011, 18:35
soo..
also ich habe jetzt alles noch ein bisschen angepasst.
Ich hab jetzt alles auf array of Bytes aufgebaut und nicht mehr auf Pointern. außerdem habe ich den "getmem"-befehl in mein "input" gepackt damit der speicherplatz nur dann reserviert wird wenn er auch wirklich gebraucht wird. außerdem habe ich in meinem "input" jetzt noch eine abfrage mit drin, in der geprüft wird ob schon einmal daten hineingepackt wurden, sollte das der fall sein gebe ich den alten speicherbereich erst wieder frei bevor neuer reserviert wird.
und statt "init" habe ich jetzt "create" verwendet und die parameter angehängt.
allerdings wirft mein "Destroy" noch eine "invalid pointer operation" fehlermeldung und ich hab im moment noch keine idee warum.
da muss irgendwas an dem FreeMem(_Data); falsch sein



Delphi-Quellcode:
unit U_Data;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs;

type

TArByte = array of Byte;

TDataType = (dtNone, dtBool, dtByte, dtChar, dtString, dtInteger, dtReal);

TData = class
 private
  _Data, _TempData : TArByte;
  _MaxSize, _RealSize: Integer;
  _DataType : TDataType;
  _DataUsed : Boolean;
 public

  property MaxSize: Integer read _MaxSize;
  property RealSize: Integer read _RealSize;
  property DataType: TDataType read _DataType;
  property DataUsed: Boolean read _DataUsed;

  constructor Create(MaxSize : Integer; DataType : TDataType);
  destructor Destroy; override;

  procedure Input(Data : TArByte; DataSize : Integer);
  procedure Output(var Data : TArByte);

  //---

  procedure InputBool(B : Boolean);
  function OutputBool : Boolean;
  procedure InputInt(I : Integer);
  function OutputInt : Integer;
  procedure InputStr(S : String);
  function OutputStr : String;

 end;

implementation

constructor TData.Create(MaxSize : Integer; DataType : TDataType);
begin
 _MaxSize := MaxSize;
 _DataType := DataType;
 _DataUsed := False;
end;

destructor TData.Destroy;
begin
 FreeMem(_Data);
end;

procedure TData.Input(Data : TArByte; DataSize : Integer);
begin
 if RealSize <= _MaxSize then
  begin
   if DataUsed then
    FreeMem(_Data)
   else
    _DataUsed := true;
   _RealSize := DataSize;
   Move(Data, _Data, DataSize);
  end
 else
  ShowMessage('Speicherplatz überschritten!');
end;

procedure TData.Output(var Data : TArByte);
var
 I : Integer;
begin
 //For I := 0 to _RealSize - 1 do
  //Data[I] := _Data[I];
 Move(_Data, Data, _RealSize)
end;

//---

procedure TData.InputBool(B : Boolean);
begin

end;

function TData.OutputBool : Boolean;
begin

end;

procedure TData.InputInt(I : Integer);
begin

end;

function TData.OutputInt : Integer;
begin

end;

procedure TData.InputStr(S : String);
var
 I,Len : Integer;
begin
 len := length(S);
 SetLength(_TempData, len);
 for I := 0 to len - 1 do
  _TempData[I] := ord(S[I+1]);
 Input(@_TempData[0], len);
end;

function TData.OutputStr : String;
var
 I : Integer;
 S : String;
begin
 SetLength(_TempData, RealSize);
 OutPut(_TempData);
 for I := 0 to RealSize - 1 do
  S := S + chr(_TempData[I]);
 Result := S;
end;


end.

unit vom hauptprogramm
Delphi-Quellcode:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, U_Data, ComCtrls, Spin;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Edit1: TEdit;
    Button4: TButton;
    GroupBox1: TGroupBox;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  D : TData;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
 D := TData.Create(500,dtString);
end;

procedure TForm1.Button2Click(Sender: TObject);
var
 arB : array of Byte;
 I,Len : Integer;
begin
 len := length(Edit1.Text);
 SetLength(arB, len);
 for I := 0 to len - 1 do
  arB[I] := ord(Edit1.Text[I+1]);
 D.Input(@arB[0], len);

end;

procedure TForm1.Button3Click(Sender: TObject);
var
 arB : TArByte;
 I : Integer;
begin
 SetLength(arB, D.RealSize);
 D.OutPut(arB);
 for I := 0 to D.RealSize - 1 do
  Caption := Caption + chr(arB[I]);
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
 D := TData.Create(500,dtString);
 D.InputStr(Edit1.Text);
 Caption := D.OutputStr;
 //D.Destroy; //führt zu invalid pointer operation
end;


end.
  Mit Zitat antworten Zitat
Andre93

Registriert seit: 10. Jun 2010
15 Beiträge
 
Delphi 6 Personal
 
#16

AW: Delphi vergisst die Werte der Eigenschaften meiner Klasse

  Alt 19. Sep 2011, 23:15
hat noch irgendjemand einen tipp, warum das destroy nicht funktioniert?
  Mit Zitat antworten Zitat
Benutzerbild von Union
Union

Registriert seit: 18. Mär 2004
Ort: Luxembourg
3.492 Beiträge
 
Delphi 7 Enterprise
 
#17

AW: Delphi vergisst die Werte der Eigenschaften meiner Klasse

  Alt 19. Sep 2011, 23:20
Wie wärs mit inherited Destroy in der letzten Zeile der Kompostierung?
Ibi fas ubi proxima merces
sudo /Developer/Library/uninstall-devtools --mode=all
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.071 Beiträge
 
Delphi 12 Athens
 
#18

AW: Delphi vergisst die Werte der Eigenschaften meiner Klasse

  Alt 19. Sep 2011, 23:39
Man ruft Destroy nicht direkt auf
Dafür gibt es Free.

Dynamische Arrays werden automatisch initialisiert und auch automatisch freigegeben.
> schmeiß das FreeMem(_Data); aus deinem Destructor raus.

A: dynamische Arrays werden eh nicht über FreeMem freigegeben

B: wenn du es schon "so" freigibst, dann setze auch die Variable auf einen Zustand, welcher "freigegeben" bedeutet.
> nil ... aber nicht über ... := nil; denn dieses würde Delphi verannlassen es freizugeben, was du ja schon gemacht hattest.


Grund für deinen Fehler:
- du versuchst das Array "falsch" feizugeben (welches vermutlich knallt)
- und selbst wenn das Freigeben funktionierte, dann versucht Delphi das nochmals, da es denkt es wäre nich nicht freigegeben, da du in der Variable den falschen Status (Pointer) zurückgelassen hattest, was dann auf jedenfall fehlschlagen würde.

Das ist so, als wenn man zweimal .Free auf eine Objektvariable aufrufen würde, ohne diese jeweils auf nil zu setzen.
Wobei Destroy nichtmal prüfen würde, womit es egal wäre es auf nil zu setzen, da es immer knallen würde.


Warum willst du überhaupt _Data an den vielen Stellen über FreeMem freigeben?
Hattest du es denn jemals über GetMem reserviert?
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.

Geändert von himitsu (19. Sep 2011 um 23:41 Uhr)
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 2 von 2     12   


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 11:58 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