Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Freigeben -> AV; Bearbeiten -> Nichts weiter (https://www.delphipraxis.net/129669-freigeben-av%3B-bearbeiten-nichts-weiter.html)

xZise 23. Feb 2009 16:55


Freigeben -> AV; Bearbeiten -> Nichts weiter
 
Hallo ihr,

ich habe ein seltsames Problem mit einem Schulprojekt. Und zwar habe ich eine von TObjectList abgeleitete Liste welche Objekte vom Typ TExemplarZeile beinhalten. Diese hat als Vorfahre die Klasse TZeile. Jetzt gibt es noch eine zweite ListenKlasse welche Objekte von Typus TKursZeile aufnimmt. Wenn ich nun die erste mit Daten fülle, kann ich nicht mehr das erste Objekt der zweiten Liste löschen oder freigeben. Weil dann kommt mir einen AV entgegen. Ansonsten kann ich damit arbeiten wie ich will. Wenn ich sogar das Objekt vorher entferne und dann die andere Liste befülle funktioniert alles wunderbar.

Delphi-Quellcode:
Kursliste.LadeAusDatenbank(Datenbank);
// An dieser Stelle funktionieren folgende Aufrufe (natürlich nicht alle gleichzeitig)
Kursliste[0].Free;
// Oder
Kursliste.Delete(0);
Exemplarliste.LadeAusDatenbank(Datenbank);
// Hier aber nicht mehr
Kursliste[0].Free;
// Oder
Kursliste.Delete(0);
Das macht "Exemplarliste.LadeAusDatenbank":
Delphi-Quellcode:
procedure TExemplareZeilenListe.LadeAusDatenbank(const ADatenbank : TDatenbank);
var
  Daten : TExemplarZeile;
  i : Integer;
  ILExemplarIDs, ILPersonenIDs, ILBuchIDs, ILBEIDs : TIntegerList;
  BLAusgedruckt : TBooleanList;
begin
  Clear;
  ILExemplarIDs := TIntegerList.Create;
  ILPersonenIDs := TIntegerList.Create;
  ILBuchIDs := TIntegerList.Create;
  ILBEIDs := TIntegerList.Create;
  BLAusgedruckt := TBooleanList.Create;
  try
    ADatenbank.GibExemplarIDs(ILExemplarIDs);
    ADatenbank.IstAusgedruckt(BLAusgedruckt, ILExemplarIDs);
    ADatenbank.GibBuchIDs(ILBuchIDs, ILExemplarIDs);
    ADatenbank.GibBEIDs(ILBEIDs, ILExemplarIDs);
    ADatenbank.GibPersonen(ILPersonenIDs, ILExemplarIDs);

    for i := 0 to ILExemplarIDs.Count - 1 do
    begin
      Daten := TExemplarZeile.Create;
      Daten.ID := ILExemplarIDs[i];
      Daten.Ausgeliehen := nil;
      Daten.Buch := nil;
      Daten.VPersonenID := ILPersonenIDs[i];
      Daten.VBuchID := ILBuchIDs[i];
      Daten.BEID := ILBEIDs[i];
      Daten.Ausgedruckt := BLAusgedruckt[i];
      Add(Daten);
    end;
  finally
    ILExemplarIDs.Free;
    ILPersonenIDs.Free;
    ILBuchIDs.Free;
    ILBEIDs.Free;
    BLAusgedruckt.Free;
  end;
end;
Ich versuche weiterhin das weiter einzugrenzen, aber im Moment möchte ich euch nicht den ganzen Sourcecode geben. Aber vielleicht hilft euch das schon? Besonders, warum man nicht freigeben kann, aber beispielsweise Werte ändern kann.

MfG
xZise

jaenicke 23. Feb 2009 17:42

Re: Freigeben -> AV; Bearbeiten -> Nichts weiter
 
Was mir spontan dazu einfällt ohne genauer in den Quelltext geschaut zu haben ist die Eigenschaft OwnsObjects. Wenn du die Objekte selbst freigeben willst, etc., dann musst du die auf False setzen. Wenn die TObjectList bei einem Delete oder der Zerstörung der Liste diese selbst aus dem Speicher entfernen soll, dann muss das auf True stehen.

xZise 23. Feb 2009 17:57

Re: Freigeben -> AV; Bearbeiten -> Nichts weiter
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo Sebastian,
OwnObjects ist bei diesen Listen auf true. Aber daran dürfte es nicht liegen, wobei ich da misstrauisch geworden bin :mrgreen: Naja ich habe mich mal daran gesetzt den Code zu entschlacken. Und das Ergebnis hänge ich einfach mal an!

Übrigens ist der Fehler (oder ein anderer?) wo anders. Ich bin der Sache mal auf der Spur.

[edit]Damit ihr wisst wo ihr suchen solltet:
Der Ursprüngliche Fehler tritt in Zeile 39 in UHaupt.pas auf.
Der neue Fehler (oder vielleicht zeigt sich der gleiche einfach anders) in Zeile 207 in UZeilen.pas bzw die Fehlermeldung erscheint, wenn man mit dem Debuger gerade über Zeile 2136 läuft.[/edit]

[edit]Ich bitte alle die es sich bereits heruntergeladen haben, die "db"-Datei zu löschen und durch diese hier im Anhang zu ersetzen.[/edit]

[edit]Folgendes:
In der Schule unter Delphi 2009 --> Fehler beim Zerstören
In der Schule unter Turbo Delphi --> Fehler beim Erstellen aber keinen beim Zerstören des KursEintrages (Z. 39 UHaupt.pas) --> Zerstören der BLAusgedruckt-Liste (Z. 229 UZeilen.pas)[/edit]

MfG
xZise

xZise 24. Feb 2009 12:49

Re: Freigeben -> AV; Bearbeiten -> Nichts weiter
 
Hallo,

wenn ich die alte Variante von meiner UIntegerList/UBooleanList verwende, bekomme ich keine Fehler. Also vermute ich die Probleme dort.

Aber ich weiß nicht, was ich da falsch mache.

MfG
xZise

xZise 25. Feb 2009 21:58

Re: Freigeben -> AV; Bearbeiten -> Nichts weiter
 
Ich möchte ja nicht stören, wüsste aber gerne, was ich da verbrochen habe :)

MfG
xZise

dataspider 26. Feb 2009 07:54

Re: Freigeben -> AV; Bearbeiten -> Nichts weiter
 
Hi,

vielleicht bin ich ja völlig auf dem falschen Dampfer, aber dein Code muss eine Exception werfen, wenn OwnObjects True ist:

Delphi-Quellcode:
Kursliste[0].Free;
// Oder
Kursliste.Delete(0);
Aus TObjectList:

Delphi-Quellcode:
procedure TObjectList.Notify(Ptr: Pointer; Action: TListNotification);
begin
  if OwnsObjects then
    if Action = lnDeleted then
      TObject(Ptr).Free;
  inherited Notify(Ptr, Action);
end;
TObject(Ptr) hast du ja schon freigegeben.

Cu, Frank

jaenicke 26. Feb 2009 11:29

Re: Freigeben -> AV; Bearbeiten -> Nichts weiter
 
Das habe ich oben ja auch schon geschrieben und das passiert ja auch. Wenn die Zeile drin ist, dann gibts den Fehler wie nicht anders zu erwarten beim Zerstören von Kursliste.

Wenn dieser Fehler nicht drin ist, dann tritt der Fehler laut Callstack und Debuggen im CPU-Fenster beim Finalisieren einer Unit auf. Genaueres hab ich jetzt eben noch nicht gesehen.

// EDIT:
Um genau zu sein tritt der Fehler in DoneControls auf, aber:
Es werden auch einige Speicherlecks gemeldet... Um die solltest du dich einmal kümmern, Details sagt dir z.B. FastMM.

xZise 26. Feb 2009 11:46

Re: Freigeben -> AV; Bearbeiten -> Nichts weiter
 
Hallo Sebastian und Frank,

Zitat:

Zitat von jaenicke
// EDIT:
Um genau zu sein tritt der Fehler in DoneControls auf, aber:
Es werden auch einige Speicherlecks gemeldet... Um die solltest du dich einmal kümmern, Details sagt dir z.B. FastMM.

Wann kommen die Speicherlecks? Nachdem der Fehler kommt? Naja wenn man davon ausgeht dass er das Objekt nicht zerstören konnte?

Zitat:

Zitat von jaenicke
Das habe ich oben ja auch schon geschrieben und das passiert ja auch. Wenn die Zeile drin ist, dann gibts den Fehler wie nicht anders zu erwarten beim Zerstören von Kursliste.

Zitat:

Zitat von dataspider
Hi,

vielleicht bin ich ja völlig auf dem falschen Dampfer, aber dein Code muss eine Exception werfen, wenn OwnObjects True ist:

Delphi-Quellcode:
Kursliste[0].Free;
// Oder
Kursliste.Delete(0);

Man beachte das Kommentar. Es ist egal, welchen Befehl ich von beiden ausführe. Bei "Delete(0)" dürfte ja auch kein Fehler kommen.

Und wie gesagt. Es kann zufall sein, dass er nur mit der Integer-/BooleanList im Anhang auftritt.

MfG
xZise

jaenicke 26. Feb 2009 12:01

Re: Freigeben -> AV; Bearbeiten -> Nichts weiter
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von xZise
Wann kommen die Speicherlecks? Nachdem der Fehler kommt? Naja wenn man davon ausgeht dass er das Objekt nicht zerstören konnte?

Alles wird erfolgreich abgearbeitet, erst nach dem eigentlichen FormDestroy tritt eine Zugriffsverletzung bei Adresse 0 auf.

Im Anhang liegt der entsprechende delphiinterne Report.

xZise 26. Feb 2009 16:00

Re: Freigeben -> AV; Bearbeiten -> Nichts weiter
 
Liste der Anhänge anzeigen (Anzahl: 2)
Tach Sebastian,

aber das hat dann nichts mehr mit freigeben zu tun. Weil folgender Code funktioniert:
Delphi-Quellcode:
procedure TFLiberate.FormCreate(Sender: TObject);
begin
  Datenbank := TDatenbank.Create(ExtractFilePath(ParamStr(0)) +  'db');
  ReportMemoryLeaksOnShutdown := true;

  Exemplarliste := TExemplareZeilenListe.Create;
  Kursliste := TKursZeilenListe.Create;

  Kursliste.LadeAusDatenbank(Datenbank);
  Exemplarliste.LadeAusDatenbank(Datenbank);
end;

procedure TFLiberate.FormDestroy(Sender: TObject);
begin
  Exemplarliste.Free;
  Kursliste.Free;

  Datenbank.Free;
end;
Deshalb denke ich, dass irgendwo in der TIntegerList, TBooleanList oder TMainList sein müsste (ich wiederhole mich :) ). Ich hänge einfach die alte Version der TInteger-/TBooleanList an, womit es funktioniert. (Kleiner Hinweis: UMainList dann in der UDatenbank entfernen)

MfG
xZise

angos 26. Feb 2009 16:49

Re: Freigeben -> AV; Bearbeiten -> Nichts weiter
 
Hi,

ich hatte schon 2, 3 Male ein ähnliches Phänomen. Selbst bei noch eindeutigeren "Nicht-Fehlern" im Code :)

eine Funktion hat eine Exception geworfen. Zum prüfen habe ich folgende Änderungen im Code vorgenommen:

Delphi-Quellcode:
function XYZ;
var
  s: string; // geändert
  i: Integer;
begin
  [...]
  s := IntToStr(i); // geändert
  [...]
  ShowMessage(s); // geändert
  [...]
end;
danach kam die Exception nicht mehr.
Auskommentieren dieser Zeilen hat die Exception zurückgebracht. Bei mir im Betrieb waren alle Entwickler ratlos.
Also habe ich mal alle *.dcu und ProjektName.* außer der Projektname.dpr.

Danach Projekt neu erzeugt und alles hat wieder einwandfrei funktioniert.

Vielleicht verschluckt sich Delphi bei dir auch an irgend wo einer Kleinigkeit.


Gruß

Ansgar

jaenicke 26. Feb 2009 17:16

Re: Freigeben -> AV; Bearbeiten -> Nichts weiter
 
Das sind meistens alles Symptome für Speicherprobleme. Leider tritt, wenn man den falschen Speicher überschreibt z.B., der Fehler oft am anderen Ende des Projekts auf und ist dort unerklärlich.
Und leider ist so etwas nicht unbedingt reproduzierbar.

Und leider können ganz andere Änderungen, die eigentlich nichts damit zu tun haben das Problem verdecken. Sei es eine zusätzliche Variable, ein zusätzlicher Befehl, der eigentlich gar nix macht, oder sowas.
Eine nicht computerbezogene Erklärung habe ich dazu einmal hier geschrieben:
http://www.delphi-forum.de/viewtopic...=527022#527022

Deshalb sind die Hinweise von Delphi auf Speicherlecks sehr Ernst zu nehmen. Irgendetwas stimmt da definitiv nicht. Ich habe nur gerade bis eben an einem eigenen Projekt gearbeitet, so dass ich mich da nicht drum kümmern konnte. Ich schau es mir gleich noch einmal genauer an.

xZise 26. Feb 2009 17:48

Re: Freigeben -> AV; Bearbeiten -> Nichts weiter
 
Zitat:

Zitat von jaenicke
Das sind meistens alles Symptome für Speicherprobleme. Leider tritt, wenn man den falschen Speicher überschreibt z.B., der Fehler oft am anderen Ende des Projekts auf und ist dort unerklärlich.
Und leider ist so etwas nicht unbedingt reproduzierbar.

Genau das ist das Problem, und genau deshalb glaube ich, dass ich irgendwo in den Listen unsauber gearbeitet habe.

Zitat:

Zitat von jaenicke
Deshalb sind die Hinweise von Delphi auf Speicherlecks sehr Ernst zu nehmen. Irgendetwas stimmt da definitiv nicht. Ich habe nur gerade bis eben an einem eigenen Projekt gearbeitet, so dass ich mich da nicht drum kümmern konnte. Ich schau es mir gleich noch einmal genauer an.

Genau deshalb verwenden wir im eigentlich Projekt die alten Varianten, aber die neue ist halt (meiner Meinung nach) besser :P
Da der Fehler auftritt, wenn ich eine von beiden neuen Listen verwende, glaube ich, liegt es an der TMainList.

MfG
xZise

jaenicke 26. Feb 2009 18:36

Re: Freigeben -> AV; Bearbeiten -> Nichts weiter
 
Was mir auffällt:
Delphi-Quellcode:
procedure TMainList.Clear;
begin
  FCount := 0;
  case FReserveManagment of
    rmExact, rmProgressive: begin
      FReservedLength := 0;
    end;
  end;
end;

und

destructor TMainList.Destroy;
begin
  inherited;
end;
Müsste nicht in beiden Fällen Speicher freigegeben werden?

xZise 26. Feb 2009 19:40

Re: Freigeben -> AV; Bearbeiten -> Nichts weiter
 
Also ich bin mir da nicht so sicher. Bei Clear sollte ich das Array wirklich einmal resizen. Aber ansonsten ist das ja ein dynamisches array von TVarRec, welches ja an sich automatisch "freigegeben" wird?

MfG
xZise

jaenicke 26. Feb 2009 19:47

Re: Freigeben -> AV; Bearbeiten -> Nichts weiter
 
Naja, was heißt automatisch freigegeben, ich sehe kein SetLength(..., 0), und das müsste da eigentlich irgendwo stehen. Denn sonst gibts doch erstmal noch eine Referenz auf die Objekte und der Referenzzähler wird nach dem Freigeben der Liste nicht 0. Denn deren Freigabe zerstört zwar die Referenzen, aber das passiert ja nicht explizit.

Ich hab gerade mal in die Implementierung von TList geschaut, daran solltest du dich vielleicht orientieren:
Delphi-Quellcode:
destructor TList.Destroy;
begin
  Clear;
end;

procedure TList.Clear;
begin
  SetCount(0);
  SetCapacity(0);
end;
Das heißt da wird durchaus explizit gelöscht.

Sicher bin ich mir über die Interna der Referenzzählung aber aus dem Kopf auch nicht, da schaue ich immer in den generierten Assemblercode, wenn ich nicht sicher bin. ;-)

xZise 26. Feb 2009 19:50

Re: Freigeben -> AV; Bearbeiten -> Nichts weiter
 
Okay habe ich eigentlich auch:
Delphi-Quellcode:
destructor TMainList.Destroy;
begin
  Clear;
  ResizeArray(0);
  inherited;
end;

procedure TMainList.Clear;
begin
  FCount := 0;
  case FReserveManagment of
    rmExact, rmProgressive: begin
      FReservedLength := 0;
    end;
  end;
  ResizeArray(FReservedLength);
end;
Aber es kommt weiterhin der Fehler und die Speicherlecks sind weiterhin vorhanden.

MfG
xZise

jaenicke 26. Feb 2009 19:52

Re: Freigeben -> AV; Bearbeiten -> Nichts weiter
 
Um genauer zu schauen wo die Speicherlecks liegen solltest du dir einmal FastMM anschauen und die Überprüfung aktivieren.

Und dann gibts da noch madExcept oder EurekaLog, die zum Debuggen sehr gut sind.

dataspider 27. Feb 2009 06:48

Re: Freigeben -> AV; Bearbeiten -> Nichts weiter
 
Hi,

mir ist beim Lesen auch noch etwas aufgefallen:

Delphi-Quellcode:
procedure TIntegerListList.Delete(const AIndex: Integer);
begin
  // next condition can not be True - or statt and
  // genau so in: TIntegerListList.GetIntegerLists
  if (AIndex < 0) and (AIndex >= Count) then
    raise EIntegerListListError.CreateFmt(SListIndexError, [AIndex]);
  FIntegerLists.Delete(AIndex);
  FHeadInteger.Delete(AIndex);
  Dec(FCount);
end;
Delphi-Quellcode:
procedure TZeilenListe.Delete(AIndexes: TIntegerList);
var
  i: Integer;
begin
  for i := 0 to AIndexes.Count - 1 do
    Delete(AIndexes[i]);
end;
Kannst du garantieren, dass AIndexes absteigend sortiert ist? Sonst löscht du die falschen oder bist plötzlich ausserhalb des Bereiches.

Cu, Frank

xZise 27. Feb 2009 07:22

Re: Freigeben -> AV; Bearbeiten -> Nichts weiter
 
Ah okay.

Normalerweise denke ich immer an die Rückwärtige Schleife. Ich probiere es gleich mal aus!

Aber du meinst die falsche TIntegerListList ^^, aber wenn ich die Schleife in UZeilen umdrehe hat das keine Auswirkung.

Und wie sieht es mit FastMM aus? Also ich habe mir jetzt FastMM4 gedownloadet, aber wie erhalte ich genauere Angaben?

MfG
xZise

jaenicke 27. Feb 2009 16:03

Re: Freigeben -> AV; Bearbeiten -> Nichts weiter
 
Zitat:

Zitat von xZise
Also ich habe mir jetzt FastMM4 gedownloadet, aber wie erhalte ich genauere Angaben?

Vom Download nicht, einbinden musst du es schon in die uses. :mrgreen:

Schau mal in die FastMM4Options.inc, da gibts nen paar Optionen. Bei Speicherlecks sollte eine Logdatei automatisch erstellt werden, wenn du das Programm im Debugger startest. Wenn das Log auch außerhalb von Delphi erstellt werden soll, gibts da glaube ich die Option RequireDebuggerPresentForLeakReport oder so.

xZise 27. Feb 2009 18:23

Re: Freigeben -> AV; Bearbeiten -> Nichts weiter
 
Naja ich hatte es gedownloadet und entpackt und zu der Form sowie zum Projekt (an erster Stelle) "FastMM4" hinzugefügt. Aber weiter kam ich dann halt nicht.

MfG
xZise

xZise 28. Feb 2009 13:10

Re: Freigeben -> AV; Bearbeiten -> Nichts weiter
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo ihr,

ich habe es nun hingekriegt die Fehlermeldung auszugeben. Das Ergebnis ist im Anhang. Eine Sache: Ich habe den Code etwas verändert.

In UHaupt:
Delphi-Quellcode:
procedure TFLiberate.FormCreate(Sender: TObject);
begin
  Datenbank := TDatenbank.Create(ExtractFilePath(ParamStr(0)) +  'db');
  ReportMemoryLeaksOnShutdown := true;

  Exemplarliste := TExemplareZeilenListe.Create;
  Kursliste := TKursZeilenListe.Create;

  Exemplarliste.LadeAusDatenbank(Datenbank);
end;
In UZeilen:
Delphi-Quellcode:
procedure TExemplareZeilenListe.LadeAusDatenbank(const ADatenbank : TDatenbank);
var
  Daten : TExemplarZeile;
  i : Integer;
  ILExemplarIDs, ILPersonenIDs, ILBuchIDs, ILBEIDs : TIntegerList;
  BLAusgedruckt : TBooleanList;
begin
  inherited;
  ILExemplarIDs := TIntegerList.Create;
  ILPersonenIDs := TIntegerList.Create;
  ILBuchIDs := TIntegerList.Create;
  ILBEIDs := TIntegerList.Create;
  BLAusgedruckt := TBooleanList.Create;
  try
    ADatenbank.GibExemplarIDs(ILExemplarIDs);
  finally
    ILExemplarIDs.Free;
    ILPersonenIDs.Free;
    ILBuchIDs.Free;
    ILBEIDs.Free;
    BLAusgedruckt.Free;
  end;
end;
Wenn ich den letzten Datenbank Aufruf auch noch entfernen würde, würde kein Fehler mehr kommen.

MfG
xZise

jaenicke 28. Feb 2009 13:43

Re: Freigeben -> AV; Bearbeiten -> Nichts weiter
 
Die Leaks sind zwar unschön, aber schlecht sind vor allem die ersten beiden Fehler. Diese verursachen auch die Fehler. Diese zeigen, dass da Speicher tatsächlich überschrieben wird.

Jetzt müsste der Stacktrace mit den Adressen verglichen werden, dafür gibts auch die Möglichkeit eine Map Datei zu erzeugen. Ob FastMM da noch mehr Details kann, weiß ich nicht.

xZise 28. Feb 2009 14:59

Re: Freigeben -> AV; Bearbeiten -> Nichts weiter
 
Hallo Sebastian,
ich vermute es liegt am ehesten an den "Move"-Befehlen. Ich werde mal gucken, in wie fern ich da was rausbekomme.

Okay, ich habe alle "Move"-Befehle manuell implementiert (in TMainList!) und es funktioniert. Wobei nur das "Move" in "MoveContent" aufgerufen wird:
Delphi-Quellcode:
procedure TMainList.MoveContent(const AFrom, ATo, ASize: Integer);
var
  i, ValueCount: Integer;
  ValueBuffer : TVarRecArray;
begin
  // Problemstelle !
  //Move(FValues[AFrom], FValues[ATo], ASize);
  //exit;
  ValueCount := ASize div SizeOf(TVarRec);
  SetLength(ValueBuffer, ValueCount);
  for i := 0 to ValueCount - 1 do
    ValueBuffer[i] := FValues[AFrom + i];

  for i := 0 to ValueCount - 1 do
    FValues[ATo + i] := ValueBuffer[i];
end;
So funktioniert es. Wenn ich aber die Kommentarezeichen entferne, bekomme ich Fehler.

Ich verwende "Move" auch im Add(TVarRecArray) sowie im Assign. Aber wie gesagt, das wird nicht aufgerufen in dieser Konstellation. Ich glaube ich werde das in eine extra "TXList"-Stressunit umbauen.

Aber ist den hier nicht "Move" möglich?

MfG
xZise

jaenicke 28. Feb 2009 18:35

Re: Freigeben -> AV; Bearbeiten -> Nichts weiter
 
Doch, eigentlich geht das so. Prüf am besten vorher und nachher den Inhalt einmal im Debugger.

xZise 28. Feb 2009 21:48

Re: Freigeben -> AV; Bearbeiten -> Nichts weiter
 
Eigentlich ist der Inhalt immer in Ordnung.

MfG
xZise

xZise 7. Mär 2009 14:55

Re: Freigeben -> AV; Bearbeiten -> Nichts weiter
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo ich bins wieder,

ich habe jetzt hier eine "Stresstest"-Version.

Bei mir kann ich nur IntegerList verwenden ohne Fehlermeldungen.

MfG
xZise

Blup 9. Mär 2009 13:38

Re: Freigeben -> AV; Bearbeiten -> Nichts weiter
 
Move sollte man in Verbindung mit Variablen deren Inhalt eine Referenzzählung erfordert nicht einsetzen.
Das betrifft insbesondere Daten die Strings oder Interface enthalten.

xZise 9. Mär 2009 16:48

Re: Freigeben -> AV; Bearbeiten -> Nichts weiter
 
Also alternativ jeden einzelnen Wert kopieren? Oder gibt es eine "bessere" Alternative?

MfG
xZise

jaenicke 9. Mär 2009 17:24

Re: Freigeben -> AV; Bearbeiten -> Nichts weiter
 
Naja, wenn man sich das alles richtig überlegt, dann kann man das so auch machen, man muss aber dann genau schauen welchen Speichern man reserviert und freigibt usw., da müsste man sich dann selbst drum kümmern.
Wenn man nicht ein Array in der Länge verändert, sondern direkt den Speicher manipuliert, dann berührt dies den Referenzzähler nicht. Denn die alten Referenzen werden nicht entfernt sondern nur direkt inkl. Referenzzähler an die neue Stelle kopiert. Bei den alten wird der Speicher wieder freigegeben ohne, dass die Referenzzähler dekrementiert werden.

Auf diese Weise sollte das klappen, ist aber noch mehr Handarbeit und man muss noch mehr aufpassen was man eigentlich tut.

Blup 11. Mär 2009 09:48

Re: Freigeben -> AV; Bearbeiten -> Nichts weiter
 
Das könnte so aussehen:

Delphi-Quellcode:
procedure MoveElements(var Source, Dest; ASize: DWord);
var
  BufferSize: DWord;
  Buffer, P1, P2: Pointer;
begin
  P1 := @Dest;
  P2 := @Source;
  if DWord(@Source) < DWord(@Dest) then
  begin
    BufferSize := DWord(@Dest) - DWord(@Source);
    if BufferSize > ASize then
      BufferSize := ASize
    else
      Inc(DWord(P1), ASize - BufferSize);
  end
  else if DWord(@Source) > DWord(@Dest) then
  begin
    BufferSize := DWord(@Source) - DWord(@Dest);
    if BufferSize > ASize then
      BufferSize := ASize
    else
      Inc(DWord(P2), ASize - BufferSize);
  end
  else
    Exit;

  GetMem(Buffer, BufferSize);
  Move(P1^, Buffer^, BufferSize);
  Move(Source, Dest, ASize);
  Move(Buffer^, P2^, BufferSize);
  FreeMem(Buffer);
end;

procedure TMainList.MoveContent(const AFrom, ATo, ASize: Integer);
begin
  MoveElements(FValues[AFrom], FValues[ATo], ASize);
end;
Die Grenzen des Arrays dürfen durch ASize natürlich nicht überschritten werden.
Deshalb würde ich MoveContent so ändern, dass ACount übergeben wird.

Delphi-Quellcode:
procedure TMainList.MoveContent(const AFrom, ATo, ACount: DWord);
begin
{$ifdef DEBUG}
  if (AFrom + ACount > Length(FValues)) or
     (ATo  + ACount > Length(FValues)) then
    raise Exception.Create('MoveContent -> Index überschreitet das Maximum');
{$endif}
  MoveElements(FValues[AFrom], FValues[ATo], ACount * SizeOf(FValues[0]));
end;

xZise 26. Mär 2009 18:00

Re: Freigeben -> AV; Bearbeiten -> Nichts weiter
 
Hi Blup,

Entschuldige das ich erst jetzt antworte, aber kann es sein, das du ASize als "Length" interpretiert hast?

MfG
xZise

Blup 27. Mär 2009 07:19

Re: Freigeben -> AV; Bearbeiten -> Nichts weiter
 
ASize wird in MoveElements als (Anzahl der zu verschiebenden Elemente) * SizeOf(Element) angenommen.

Ich habe aber vorgeschlagen MoveContent so zu verändern, dass nur die Anzahl der Elemente übergeben wird.
Das ist für die Verwendung einfacher und an einer zentralen Stelle kann so leicht die Überprüfung auf fehlerhafte Parametern erfolgen.


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