Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Risiko dyn.array als Funktionsrückgabewert ??? (https://www.delphipraxis.net/166988-risiko-dyn-array-als-funktionsrueckgabewert.html)

bernhard_LA 8. Mär 2012 14:25

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:
aList : :TINTEGERList2D ;
           bList : :TINTEGERList2D ;


aList[i,j] := Blist [u,v];
ein mögliche Ursache ?

himitsu 8. Mär 2012 14:47

AW: Risiko dyn.array als Funktionsrückgabewert ???
 
Delphi-Quellcode:
aList[i,j] := Blist [u,v];
Ist ja im Endeffekt nur eine einfache Integerzuweisung und macht keine Probleme.
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:
aList := bList;
oder
Delphi-Quellcode:
aList[i] := bList[u];
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.

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

bernhard_LA 8. Mär 2012 15:29

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:

uligerhardt 8. Mär 2012 15:31

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:
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.
bei mir
Code:
Return: 0 10
var:    0 10
out:    0  0
DynArray-Rückgabewerte werden also nicht korrekt initialisiert!

Peter1999 8. Mär 2012 16:11

AW: Risiko dyn.array als Funktionsrückgabewert ???
 
Zitat:

DynArray-Rückgabewerte werden also nicht korrekt initialisiert!
Wieso? Was hättest du denn da anderes erwartet?

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?

himitsu 8. Mär 2012 16:42

AW: Risiko dyn.array als Funktionsrückgabewert ???
 
Zitat:

Zitat von Peter1999 (Beitrag 1155430)
Zitat:

DynArray-Rückgabewerte werden also nicht korrekt initialisiert!
Wieso? Was hättest du denn da anderes erwartet?

Mit der Speicherverwaltung gibt es eigentlich keine Probleme.

Aber mit der Initialisierung muß man aufpassen.
http://www.delphipraxis.net/166950-s...ml#post1155075 (#16-#18)

uligerhardt 8. Mär 2012 16:45

AW: Risiko dyn.array als Funktionsrückgabewert ???
 
Zitat:

Zitat von Peter1999 (Beitrag 1155430)
Zitat:

DynArray-Rückgabewerte werden also nicht korrekt initialisiert!
Wieso? Was hättest du denn da anderes erwartet?

Na halt, dass sie korrekt initialisiert werden. :mrgreen:
Eine lokale verwaltete Variable (String, dyn. Array, Interface) wird ja auch null-initialisiert.

Zitat:

Zitat von Peter1999 (Beitrag 1155430)
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?

Damit meinst du jetzt den OP, oder?

Panthrax 8. Mär 2012 16:49

AW: Risiko dyn.array als Funktionsrückgabewert ???
 
Zitat:

Zitat von uligerhardt (Beitrag 1155445)
Zitat:

Zitat von Peter1999 (Beitrag 1155430)
Zitat:

DynArray-Rückgabewerte werden also nicht korrekt initialisiert!
Wieso? Was hättest du denn da anderes erwartet?

Na halt, dass sie korrekt initialisiert werden. :mrgreen:
Eine lokale verwaltete Variable (String, dyn. Array, Interface) wird ja auch null-initialisiert.


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;

himitsu 8. Mär 2012 17:00

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.

shmia 8. Mär 2012 17:19

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 16:30 Uhr.
Seite 1 von 2  1 2      

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