![]() |
Risiko dyn.array als Funktionsrückgabewert ???
wir haben einen Datentyp
Delphi-Quellcode:
TINTEGERList2D = array of array of Integer
Im Program gibt es jede Menge an Funktionen wie
Delphi-Quellcode:
...; function Make_Something (var aList :TINTEGERList2D ) : Real; function Make_SomethingOther (x,y : Integer) : TINTEGERList2D; ...; Wir hatten das Programm schon im Einsatz, lief ganz gut. Nach den letzten Änderungen bekommen wir eine AV Delphi versucht eines unserer Felder/Listen 2 x freizugeben (lt. FASTMM4) . Nur sehen wir leider nicht die Position im Code .... und warum sehe ich erst recht nicht Sind Zuweisungen wir
Delphi-Quellcode:
ein mögliche Ursache ?
aList : :TINTEGERList2D ;
bList : :TINTEGERList2D ; aList[i,j] := Blist [u,v]; |
AW: Risiko dyn.array als Funktionsrückgabewert ???
Delphi-Quellcode:
Ist ja im Endeffekt nur eine einfache Integerzuweisung und macht keine Probleme.
aList[i,j] := Blist [u,v];
Ihr könnt aber dennoch mal, in den Projektoptionen, die Bereichsprüfung aktivieren, denn Schreibzugriffe auf nichtexistierende Fehler bereiten manchmal kleine Problemchen. :angle: Aber
Delphi-Quellcode:
oder
aList := bList;
Delphi-Quellcode:
sind da etwas anders zu betrachten, denn dyn. Arrays verfügen zwar über eine Referenzzählung, aber man hat "vergessen" diesen Arrays einen CopyOnWrite-Zugriff zu verpassen.
aList[i] := bList[u];
Wenn man bei Strings
Delphi-Quellcode:
var
s, x: string; s := '12345'; x := s; // erhöht nur die Referenzzählung x[3] := 'a'; // führt vorher ein UniqueString auf x aus, bevor geschrieben wird. ShowMessage(s + sLineBreak + x);
Delphi-Quellcode:
var
s, x: array of Integer; SetLength(s, 5); s[0] := 1; s[1] := 2; s[2] := 3; s[3] := 4; s[4] := 5; x := s; // erhöht auch nur die Referenzzählung x[2] := 666; // schreibt einfach, ohne die Referenzzählung zu prüfen ShowMessage(IntToStr(s[2]) + ' ' + IntToStr(x[2]));
Delphi-Quellcode:
...
s[4] := 5; x := Copy(s); // kopiert das array, in eine eigenständige Instanz x[2] := 666; // schreibt einfach, ohne die Referenzzählung zu prüfen ShowMessage(IntToStr(s[2]) + ' ' + IntToStr(x[2]));
Delphi-Quellcode:
...
s[4] := 5; x := s; // erhöht auch nur die Referenzzählung x := Copy(x); // sicherstellen, daß x unique ist (zur Optimierung könnte man vorher noch die referenzzählung prüfen, ob überhaupt nötig) x[2] := 666; // schreiben (die Referenzzälung wurde ja schon sichergestellt) ShowMessage(IntToStr(s[2]) + ' ' + IntToStr(x[2])); Aber so oder so, an der Referenzzählung sollte nichts kaputtgehn, abgesehn - von Bufferoverruns - wenn man die Array-Instanz-Referenzzählung direkt oder indirekt mit Pointern schrottet/umgeht |
AW: Risiko dyn.array als Funktionsrückgabewert ???
Bereichsprüfung eingeschalten -> leider kein Erfolg
innerhalb der Funktionen sind die Setlenght Commands verbaut, alle dyn. Arrays werden als var Param übergeben, bzw. als Function result abgeholt .... kann hier irgendwo ein Fehler liegen im Speichermanager ??? Wie finde ich den Fehler :cry: |
AW: Risiko dyn.array als Funktionsrückgabewert ???
Ich weiß nicht, ob das dein Problem ist, aber bei dynamischen Arrays als Rückgabewerten muss man beachten, dass sie eher als var-Parameter implementiert sind. Z.B. liefert folgendes Progrämmchen
Delphi-Quellcode:
bei mir
program DynArrayReturn;
{$APPTYPE CONSOLE} uses Types, SysUtils; function MakeArrayRet(ASize: Integer): TIntegerDynArray; begin Write(Length(Result): 3); SetLength(Result, ASize); end; procedure MakeArrayVar(var AArray: TIntegerDynArray; ASize: Integer); begin Write(Length(AArray): 3); SetLength(AArray, ASize); end; procedure MakeArrayOut(out AArray: TIntegerDynArray; ASize: Integer); begin Write(Length(AArray): 3); SetLength(AArray, ASize); end; procedure Test; var a: TIntegerDynArray; begin Write('Return:'); a := nil; a := MakeArrayRet(10); a := MakeArrayRet(5); Writeln; Write('var: '); a := nil; MakeArrayVar(a, 10); MakeArrayVar(a, 5); Writeln; Write('out: '); a := nil; MakeArrayOut(a, 10); MakeArrayOut(a, 5); Writeln; end; begin try Test; Readln; except on E: Exception do Writeln(E.Classname, ': ', E.Message); end; end.
Code:
DynArray-Rückgabewerte werden also nicht korrekt initialisiert!
Return: 0 10
var: 0 10 out: 0 0 |
AW: Risiko dyn.array als Funktionsrückgabewert ???
Zitat:
Für viel wahrscheinlicher halte ich, dass an irgendeiner Stelle der Array nicht sauber von 0..high() durchlaufen wird. Ist da versehentlich ein 1..length() dazwischen geraten? Wenn das passiert, treten die Zugriffsverletzungen leider nur selten sehr zeitnah auf und man sucht seeeehr lange. Dass es an einer doppelten Freigabe des Speichermanagers liegt, halte ich eher für unwahrscheinlich. Wie kommst du denn zu der Erkenntnis? |
AW: Risiko dyn.array als Funktionsrückgabewert ???
Zitat:
Aber mit der Initialisierung muß man aufpassen. ![]() |
AW: Risiko dyn.array als Funktionsrückgabewert ???
Zitat:
Eine lokale verwaltete Variable (String, dyn. Array, Interface) wird ja auch null-initialisiert. Zitat:
|
AW: Risiko dyn.array als Funktionsrückgabewert ???
Zitat:
Sie sind korrekt initialisiert. Funktionsrückgabewerte sind eben keine lokalen Variablen.
Delphi-Quellcode:
function F(const X: Extended): Extended; begin Result := { ... }; end;
procedure F(const X: Extended; var Result: Extended); begin Result := { ... }; end; |
AW: Risiko dyn.array als Funktionsrückgabewert ???
Ordinale Typen, Fließkommatypen und alles mögliches kleines einfaches Getier, welches in ein Register paßt und wo kein schliommes Speichermanagement dahintersteht,
das sind "richtige" Rückgabewerte und keine impliziten Out/Var-Parameter. Aber bei diesen Sachen, wie String und dyn. Array, ist das soeine Sache. |
AW: Risiko dyn.array als Funktionsrückgabewert ???
Also ich würde dyn. Arrays nur innerhalb einer Klasse umherreichen.
Sobald das dyn. Array die Grenzen einer Klasse verlässt diese Technik nicht robust genug, um Daten sicher zu transportieren. Ein dyn. Array ist wie DNS ohne eine schützende Zellwand drumrum; jeder kann (auch unabsichtliche) Änderungen vornehmen. Wenn man das dyn. Array mit einer Klasse kapselt, kann man den Zugriff auf die inneren Daten genau kontrollieren. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 03:33 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 by Thomas Breitkreuz