![]() |
Eintrag aus Array löschen funktioniert bei 64 bit nicht
Ich benutze seit einer Ewigkeit diesen Codeschnipsel und er funktioniert mit x86.
Mit x64 funktioniert er genau 2x und dann bekomme ich eine ungültige Zeigeroperation. Der Input ist immer der gleiche. Ein String mit mehreren Teilen geteilt durch |, die ich mit Explode in ein Array packe. Das klappt alles bis ich den ersten Eintrag löschen möchte. Dann kommt der Fehler.
Delphi-Quellcode:
Das Array ist immer mindestens 3 Einträge lang.
procedure DeleteArrayIndex(var AArray: TArray<string>; AIndex: Integer);
begin if AIndex > High(AArray) then Exit; if AIndex < Low(AArray) then Exit; if AIndex = High(AArray) then begin SetLength(AArray, Length(AArray) - 1); Exit; end; Finalize(AArray[AIndex]); System.Move(AArray[AIndex + 1], AArray[AIndex], (Length(AArray) - AIndex - 1) * SizeOf(string) + 1); SetLength(AArray, Length(AArray) - 1); end; if StringParts[0] = 'HEADER' then DeleteArrayIndex(StringParts, 0); // Fehler |
AW: Eintrag aus Array löschen funktioniert bei 64 bit nicht
Wofür ist denn das + 1 am Ende?
Delphi-Quellcode:
Welche Delphi Version?
System.Move(AArray[AIndex + 1], AArray[AIndex], (Length(AArray) - AIndex - 1) * SizeOf(string) + 1);
|
AW: Eintrag aus Array löschen funktioniert bei 64 bit nicht
Rio. Der Code wurde einfach von irgendwoher vor Jahren mal kopiert.
|
AW: Eintrag aus Array löschen funktioniert bei 64 bit nicht
Der Code ist meiner Meinung nach falsch - eventuell nur falsch abgeschrieben.
Das Move erwartet im dritten Parameter die Anzahl Bytes. Hier wird aus unerfindlichen Gründen 1 Byte zuviel angegeben. Der korrekte Code müsste so lauten:
Delphi-Quellcode:
System.Move(AArray[AIndex + 1], AArray[AIndex], (Length(AArray) - AIndex - 1) * SizeOf(string));
Einfacher geht es aber mit
Delphi-Quellcode:
Delete(AArray, AIndex, 1);
Siehe: ![]() |
AW: Eintrag aus Array löschen funktioniert bei 64 bit nicht
Ich vermute, er möchte noch eine trailing 0 mitschleppen. Das war vielleicht mal sinnvoll......
Gruß K-H |
AW: Eintrag aus Array löschen funktioniert bei 64 bit nicht
Hmm..
Zitat:
Und dies kann irgendetwas sein. Auch schreibt er dieses Byte dann 'hinter' das Array in einen Speicher, welcher nicht zum Array gehört und dann kann es knallen.. ;) (Edit: OK, knallen würde es hier nicht, da er das Array erst danach abschneidet.. Aber generell sollte mit Move vorsichtig umgegangen werden ;) ) |
AW: Eintrag aus Array löschen funktioniert bei 64 bit nicht
Zitat:
Ich wäre in diesem Fall aber sowieso vorsichtig, was die Referenzzählung bei Strings betrifft. Die kann mit dem Move schon mal gehörig durcheinander geraten. Selbst bei korrektem Count zeigen nach dem Move die letzten beiden Array-Elemente auf denselben String. Ich glaube kaum, daß bei dem Move auch die Referenzzählung entsprechend angepasst wird. Beim folgenden SetLength allerdings schon. Dieses Beispielprogramm verdeutlicht die Problematik und zeigt, daß die Verwendung von Delete nicht nur einfacher, sondern auch sicherer ist.
Delphi-Quellcode:
program Project490;
{$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils; function StringRefCount(const Value: string): Integer; var P: PInteger; begin P := @Value[1]; Dec(P, 2); Result := P^; end; procedure Main; var arr: TArray<string>; I: Integer; begin SetLength(arr, 10); for I := 0 to 8 do begin arr[I] := I.ToString; end; arr[9] := arr[8]; Writeln('Verwendung von Move und SetLength'); Writeln('8 und 9 zeigen auf denselben string, RefCount ist OK'); Writeln('7: ', StringRefCount(arr[7])); Writeln('8: ', StringRefCount(arr[8])); Writeln('9: ', StringRefCount(arr[9])); Move(arr[1], arr[0], 9*SizeOf(arr[0])); Writeln('nach Move: 7,8 und 9 zeigen auf denselben string, aber RefCount is 2!'); Writeln('7: ', StringRefCount(arr[7])); Writeln('8: ', StringRefCount(arr[8])); Writeln('9: ', StringRefCount(arr[9])); SetLength(arr, 9); Writeln('nach SetLength: RefCount für 9 wird runtergezählt.'); Writeln('7 und 8 zeigen auf denselben string, aber RefCount ist 1!'); Writeln('7: ', StringRefCount(arr[7])); Writeln('8: ', StringRefCount(arr[8])); arr[8] := ''; Writeln('8 ist jetzt leer, RefCount wurde erniedrigt.'); Writeln('7 zeigt immer noch auf diesen string, aber RefCount ist 0!'); Writeln('7: ', StringRefCount(arr[7])); Writeln('8: ', StringRefCount(arr[8])); Writeln; end; procedure Main2; var arr: TArray<string>; I: Integer; begin SetLength(arr, 10); for I := 0 to 8 do begin arr[I] := I.ToString; end; arr[9] := arr[8]; Writeln('Verwendung von Delete'); Writeln('8 und 9 zeigen auf denselben string, RefCount ist OK'); Writeln('7: ', StringRefCount(arr[7])); Writeln('8: ', StringRefCount(arr[8])); Writeln('9: ', StringRefCount(arr[9])); Delete(arr, 0, 1); Writeln('nach Delete: RefCount für 9 wird runtergezählt.'); Writeln('7 und 8 zeigen auf denselben string, RefCount ist OK'); Writeln('7: ', StringRefCount(arr[7])); Writeln('8: ', StringRefCount(arr[8])); arr[8] := ''; Writeln('8 ist jetzt leer, RefCount wurde erniedrigt.'); Writeln('7 zeigt immer noch auf diesen string, RefCount ist OK'); Writeln('7: ', StringRefCount(arr[7])); Writeln('8: ', StringRefCount(arr[8])); Writeln; end; begin try Main; Main2; except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; Readln; end. |
AW: Eintrag aus Array löschen funktioniert bei 64 bit nicht
So würde es funktionieren:
Delphi-Quellcode:
Inzwischen ist das wie beschrieben einfacher zu lösen:
Finalize(AArray[AIndex]);
System.Move(AArray[AIndex + 1], AArray[AIndex], (Length(AArray) - AIndex - 1) * SizeOf(string)); {letzten Eintrag auf nil setzen, damit keine Referenzzählung für den jetzt doppelten Eintrag bei SetLength erfolgt} System.FillChar(AArray[Length(AArray) - 1], SizeOf(string), 0); // oder Pointer(AArray[Length(AArray) - 1]) := nil; SetLength(AArray, Length(AArray) - 1);
Delphi-Quellcode:
System.Delete(AArray, AIndex, 1);
. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:48 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