Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi TObjectList - Sort crash (D7) (https://www.delphipraxis.net/110001-tobjectlist-sort-crash-d7.html)

o-sch 11. Mär 2008 13:40


TObjectList - Sort crash (D7)
 
Hallo !

Ich habe hier eine abgeleitete TObjectList die ich mit eigenen Objekten befülle:
(Der Code ist frisiert, damit ich das Problem einfacher darstellen kann)

Delphi-Quellcode:
 
function TMyItemList.NewMyItem(a1,a2,a3:Integer):TmyItem;
begin
  Result := NIL;
  Result := TmyItem.Create(Self);
  Result.V1 := a1;
  Result.V2 := a2;
  Result.V3 := a3;
  Self.Add(Result);
end;
Soweit so gut ... Ich kann ohne Probleme auf die Objekte zugreifen:

Delphi-Quellcode:

procedure TmyItemList.SchleifMich;
var i:Integer;
begin
  for i := 0 to Self.Count-1 do
  begin
    if TmyItem(Items[i]).V1 > 0 then
      beep;
  end;
end;

Aber: Versuche ich zu sortieren bekomme, ich eine Zugriffsverletzung.
Ich würde ja vermuten, daß ich nur "gültige" Pointer also vom passenden Typ (TmyItem) in der Funktion vorfinde.
Schließlich gib es nur die eine Funktion um Objekte zuzufügen.
Das ist auch in 99% der Fälle so ... dann plötzlich finde ich einen Pointer der ins Nichts zeigt.


Delphi-Quellcode:
 
  function MyListCompare(pmyItem1, pmyItem2: pointer): integer;
  begin
    Result := 0
    if TmyItem(pmyItem).V1 > TmyItem(pmyItem).V2 then Result := 1;
    if TmyItem(pmyItem).V1 < TmyItem(pmyItem).V2 then Result := -1;
  end;


  procedure TMyItemList.DoSort
  begin
    Self.Sort(MyListCompare);
  end;

Meine Vermutung ... ich mache was beim Erzeugen falsch.
Die Funktion NewMyItem wird einmal von außen gecallt und einmal über eine Funktion im Objekt:

Delphi-Quellcode:
  Procedure TmyItemList.AddMySpecialItem;
  begin
    Self.NewMyItem(1,2,3);
  end;
versus

Delphi-Quellcode:
  procedure fmain.CallIt
  begin
    getMyItemList.NewItem(99,88,77);
  end;

Sollte doch eigentlich keinen Unterschied machen.

Ich bin ratlos :-( help, please

thkerkmann 11. Mär 2008 14:29

Re: TObjectList - Sort crash (D7)
 
Hi,
also deine compare blick ich nicht:
Zitat:

Delphi-Quellcode:
function MyListCompare(pmyItem1, pmyItem2: pointer): integer;
  begin
    Result := 0
    if TmyItem(pmyItem).V1 > TmyItem(pmyItem).V2 then Result := 1; // <<<< wo kommt denn pmyItem plötzlich her ???
    if TmyItem(pmyItem).V1 < TmyItem(pmyItem).V2 then Result := -1;
  end;

ich würde so schreiben
Delphi-Quellcode:
function MyListCompare(pmyItem1, pmyItem2: pointer): integer;
  begin
    if TmyItem(pmyItem1).V1 > TmyItem(pmyItem2).V1 then
     Result := 1
    else if TmyItem(pmyItem1).V1 < TmyItem(pmyItem2).V1 then
      Result := -1
    else
      Result := 0;
  end;

o-sch 11. Mär 2008 14:49

Re: TObjectList - Sort crash (D7)
 
Hallo !

Danke für deine Antwort.

pmyItem1 und pmyItem2 sind die übergebenen Pointer:

Delphi-Quellcode:
function MyListCompare(pmyItem1, pmyItem2: pointer): integer;
                       ^^^^^^^^^ ^^^^^^^^
Ich denke die beiden Compare-Varianten werden das gleiche Ergebnis liefern .

Die Zugriffsverletzung tritt ja auch schon beim Zugriff auf : TmyItem(pmyItem1).V1 auf.
Das ist das eigentliche Problem.

dfried 11. Mär 2008 14:59

Re: TObjectList - Sort crash (D7)
 
Zitat:

Zitat von o-sch
Hallo !
pmyItem1 und pmyItem2 sind die übergebenen Pointer:

Das ist glaub ich schon klar, nur wenn der Sourcecode den du oben aufgelistet hast per Copy & Past aus deinem Delphi ist, dann ist der Fehler, dass du dort auf ein "pmyItem" verweist und nicht auf pmyItem1 oder pmyItem2!

thkerkmann 11. Mär 2008 15:04

Re: TObjectList - Sort crash (D7)
 
Genau das hab ich gemeint :gruebel:

o-sch 11. Mär 2008 15:09

Re: TObjectList - Sort crash (D7)
 
Zitat:

Zitat von dfried
Das ist glaub ich schon klar, nur wenn der Sourcecode den du oben aufgelistet hast per Copy & Past aus deinem Delphi ist, dann ist der Fehler, dass du dort auf ein "pmyItem" verweist und nicht auf pmyItem1 oder pmyItem2!

Der Code wird nicht 1:1 benutzt, sondern ist stark vereinfacht. Das ist ein Fehler in der Fehlerbeschreibung :?

Delphi-Quellcode:
function MyListCompare(pmyItem1, pmyItem2: pointer): integer;
  begin
    Result := 0
    if TmyItem(pmyItem1).V1 > TmyItem(pmyItem2).V1 then Result := 1;
    if TmyItem(pmyItem1).V1 < TmyItem(pmyItem2).V1 then Result := -1;
  end;

thkerkmann 11. Mär 2008 15:34

Re: TObjectList - Sort crash (D7)
 
Ok,

also wenn's das nicht ist - nehmen wir mal an deine compare Funktion sei richtig - muss der Fehler woanders liegen.

Wiewohl ich deine Konstruktion von if's nicht akzeptieren kann. Das ist sowas von ineffizient, für mich gehört da ein if .. else if .. else rein

Aus dem was Du uns hier an Code gezeigt hast, können wir aber nichts entnehmen. Da wirst Du mehr rausrücken müssen.

Gruss

Tyrael Y. 11. Mär 2008 15:39

Re: TObjectList - Sort crash (D7)
 
Zitat:

Zitat von o-sch
Delphi-Quellcode:
  Procedure TmyItemList.AddMySpecialItem;
  begin
    Self.NewMyItem(1,2,3);
  end;

Was passiert da drin?

o-sch 11. Mär 2008 15:52

Re: TObjectList - Sort crash (D7)
 
Zitat:

Zitat von Tyrael Y.
Delphi-Quellcode:
  Procedure TmyItemList.AddMySpecialItem;
  begin
    Self.NewMyItem(1,2,3);
  end;

Was passiert da drin?

Schau mal ganz oben. Der erste Codeschnippsel im Startpost.
Es gibt auch nur diese eine Methode um ein Objekt zu erzeugen und der eigenen Liste zuzufügen.

@thkerkmann: Else kommt mir nicht ins Haus :zwinker:

Dax 11. Mär 2008 15:58

Re: TObjectList - Sort crash (D7)
 
Zitat:

Zitat von o-sch
@thkerkmann: Else kommt mir nicht ins Haus :zwinker:

Wieso?

Tyrael Y. 11. Mär 2008 16:02

Re: TObjectList - Sort crash (D7)
 
Zitat:

Zitat von o-sch
Delphi-Quellcode:
 
function TMyItemList.NewMyItem(a1,a2,a3:Integer):TmyItem;
begin
  Result := NIL;
  Result := TmyItem.Create(Self);
  Result.V1 := a1;
  Result.V2 := a2;
  Result.V3 := a3;
  Self.Add(Result);
end;

Was machst du ausserhalb dieser Funktion mit dem Rückgabeergebnis?
Kann es sein, daß du das Rückgabeergebnis irgendwo wieder freigibst?

o-sch 11. Mär 2008 17:51

Re: TObjectList - Sort crash (D7)
 
Zitat:

Zitat von Tyrael Y.
Delphi-Quellcode:
 
function TMyItemList.NewMyItem(a1,a2,a3:Integer):TmyItem;
begin
  Result := NIL;
  Result := TmyItem.Create(Self);
  Result.V1 := a1;
  Result.V2 := a2;
  Result.V3 := a3;
  Self.Add(Result);
end;
Was machst du ausserhalb dieser Funktion mit dem Rückgabeergebnis?
Kann es sein, daß du das Rückgabeergebnis irgendwo wieder freigibst?

Nein, leider nicht - das muss die Liste selbst machen. (OwnsObjects)

Delphi-Quellcode:
TObjectList.Create(True);
@Dax just joking

o-sch 12. Mär 2008 07:42

Re: TObjectList - Sort crash (D7)
 
Ich habe eine Workaround gefunden.
Wenn ich mach jedem Add sofort sortiere, dann läuft es zumindest durch.

Schöne und saubere Lösungen sehen anders aus :(

Delphi-Quellcode:
function TMyItemList.NewMyItem(a1,a2,a3:Integer):TmyItem;
begin
  Result := NIL;
  Result := TmyItem.Create(Self);
  Result.V1 := a1;
  Result.V2 := a2;
  Result.V3 := a3;
  Self.Add(Result);

  Self.Sort(MyListCompare);  // Workaround - fix me !

end;

Angel4585 10. Feb 2009 13:29

Re: TObjectList - Sort crash (D7)
 
Ist zwar schon bissl älter, aber ich stehe gerade vor dem selben Problem, folgende Compare Methode:
Delphi-Quellcode:
function CompareNextStart(Item1, Item2: Pointer): Integer;
begin
if(TMyItem(Item2).NextStart = 0)then Result:=1
else if(TMyItem(Item1).NextStart > TMyItem(Item2).NextStart)then Result:=0
else Result:=1;
end;
Hab allerdings keine Ahnung was genau der Wert von Result bewirkt, also was passiert wenn Result 1,0 oder -1 ist?(Die D2005 Hilfe ist [strike]etwas[/strike] grottenschlecht)

Ausserdem habe ich das gleiche Problem wie oben genannt, ich bekomme irgendwann einen Pointer übergeben welcher ins Nichts führt($16 oder so).

Hatte jemand zu dem Problem mittlerweile ne Lösung?(Möcht jetz keinen neuen Thread aufmachen da es exakt das gleiche Problem ist)

nahpets 10. Feb 2009 13:42

Re: TObjectList - Sort crash (D7)
 
Hallo,

kurz die Hilfe aus Delphi 7 per Copy&Paste, eventuell hilft es Dir weiter:
Zitat:

Zitat von Delphi 7-Hilfe
TListSortCompare (Typ)
Der Typ TListSortCompare wird für Callback-Routinen verwendet, die zwei Listeneinträge miteinander vergleichen.

Unit

Classes

Delphi-Syntax:

type TListSortCompare = function (Item1, Item2: Pointer): Integer;

C++ Syntax:

typedef int __fastcall (*TListSortCompare)(void * Item1, void * Item2);

Beschreibung

TListSortCompare ist eine Vergleichsfunktion, die einen positiven Wert zurückgibt, wenn Item1 kleiner als Item2 ist. Der Rückgabewert ist Null, wenn beide Einträge gleich sind. Wenn Item1 größer als Item2 ist, ist der Rückgabewert negativ.

Wert Beschreibung

> 0 (positiv) Item1 ist kleiner als Item2
0 Item1 ist gleich Item2
< 0 (negativ) Item1 ist größer alsItem2

Zitat:

Zitat von Angel4585
Ist zwar schon bissl älter, aber ich stehe gerade vor dem selben Problem, folgende Compare Methode:
Delphi-Quellcode:
function CompareNextStart(Item1, Item2: Pointer): Integer;
begin
if(TMyItem(Item2).NextStart = 0)then Result:=1
else if(TMyItem(Item1).NextStart > TMyItem(Item2).NextStart)then Result:=0
else Result:=1;
end;
Hab allerdings keine Ahnung was genau der Wert von Result bewirkt, also was passiert wenn Result 1,0 oder -1 ist?(Die D2005 Hilfe ist [strike]etwas[/strike] grottenschlecht)

Ausserdem habe ich das gleiche Problem wie oben genannt, ich bekomme irgendwann einen Pointer übergeben welcher ins Nichts führt($16 oder so).

Hatte jemand zu dem Problem mittlerweile ne Lösung?(Möcht jetz keinen neuen Thread aufmachen da es exakt das gleiche Problem ist)

Deine Vergleichsfunktion liefert entweder 0 oder 1, aber nicht -1, liegt dort eventuell der Fehler?

Angel4585 10. Feb 2009 13:53

Re: TObjectList - Sort crash (D7)
 
ok und wann werden die items dann getauscht? wenn 1, 0 oder -1 als ergebnis ist?
Ich habe das Problem das ich zB diese Liste:

0
1
4
3
0
6
2

so sortiert haben möchte:

1
2
3
4
6
0
0

Edit: Aaahhh probieren geht halt doch über studieren :mrgreen:

Delphi-Quellcode:
function CompareNextStart(Item1, Item2: Pointer): Integer;
begin
if(TMyItem(Item1).NextStart = 0)then Result:=1
else if(TMyItem(Item1).NextStart > TMyItem(Item2).NextStart)then Result:=1
else if(TMyItem(Item1).NextStart < TMyItem(Item2).NextStart)then Result:=-1
else Result:=0;
end;
so gehts :dp:

nahpets 10. Feb 2009 14:07

Re: TObjectList - Sort crash (D7)
 
Hallo,

ein Versuch ohne Gewähr:

Delphi-Quellcode:
function CompareNextStart(Item1, Item2: Pointer): Integer;
begin
       if (TMyItem(Item1).NextStart = 0) then Result := -99  // 0 ist im Wunschergebnis > als alles Andere.
  else if (TMyItem(Item2).NextStart = 0) then Result := 99 
  else if (TMyItem(Item1).NextStart < TMyItem(Item2).NextStart) then Result := 1 // Item1 ist < Item2
  else if (TMyItem(Item1).NextStart > TMyItem(Item2).NextStart) then Result := -1 // Item1 ist > Item2
  else Result := 0; // Item1 = Item2
end;
Getauscht wird, wenn Result <> 0.

PS: Du warst schneller als ich :(

Angel4585 10. Feb 2009 14:22

Re: TObjectList - Sort crash (D7)
 
Du hast ein anderes Ergebnis als ich ;)
Aber das getauscht wird wenn die beiden unterschiedlich sind kann ich fast nicht glauben, dann bekommt man ja nie ne sortierung hin ;)

nahpets 10. Feb 2009 14:28

Re: TObjectList - Sort crash (D7)
 
Hallo,
Zitat:

Zitat von Angel4585
Du hast ein anderes Ergebnis als ich ;)
Aber das getauscht wird wenn die beiden unterschiedlich sind kann ich fast nicht glauben, dann bekommt man ja nie ne sortierung hin ;)

schau mal (wenn Du Interesse hast) in die Classes.pas und suche dort nach TListSortCompare. Intern wird bei der Sortierung ein Quicksort verwandt. Eventuell kannst Du ja daran nachvollziehen, warum das Sortieren funktioniert.

globetrotter77 10. Feb 2009 15:48

Re: TObjectList - Sort crash (D7)
 
Sort ist eine Methode von TList, die als einzigen Parameter den Namen einer Function vom Typ TListSortCompare erwartet.
Diese Function MUSS exakt folgende Deklaration besitzen:
Delphi-Quellcode:
function funktionsname(Item1, Item2: Pointer): Integer;
TList.Sort ruft nun wiederum, falls überhaupt etwas in der Liste vorhanden ist, die interne Methode QuickSort auf, die sich rekursiv auch wieder selber aufruft, allerdings mit immer kleiner werdenden Intervallen, daher auch endlich.
Die eigentliche Sortierung erfolgt dabei durch blitzschnelles Umschlichten der auf die einzelnen Elemente zeigenden Pointer.

Nachdem die Liste selbst nicht wissen kann, nach welchen Kriterien sortiert werden soll, muss hierzu eben diese genannte Function übergeben werden, die ebenfalls nur mit den Pointern aufgerufen wird.

Hier kann man nach Herzenslust Sortiervorgaben programmieren.
Entscheidend für den intern durchlaufenen Algorithmus ist einzig und alleine, ob ein Wert rauskommt, der <0, =0 oder >0 ist
Auch wenn -7 zurückgegeben wird, wird das nicht anders behandelt als -1.

Es bedeuten:
<0 Item2 ist "kleiner" als Item1, wird also "vorher" einsortiert
=0 Item2 ist "gleich" Item1, da ist die Reihenfolge egal
>0 Item2 ist "größer" als Item1, wird also "nachher" einsortiert

Wieso so rum und nicht so, wie man's aus der Funktion herauslesen würde, weiß kein Mensch.

Wenn du also eine Spezialsortierung für die Nullwerte brauchst, muss die Funktion daher lauten (ich schreibe die Vergleiche mal andersrum, damit das Ergebnis (zumindest für mich) besser lesbar wird):
Delphi-Quellcode:
function CompareNextStart(Item1, Item2: Pointer): Integer;
begin
  if (TMyItem(Item1).NextStart = 0) and (TMyItem(Item2).NextStart <> 0) then
    Result := -1 // Item2 < Item1
  else if (TMyItem(Item2).NextStart = 0) and (TMyItem(Item1).NextStart <> 0) then
    Result := +1 // Item2 > Item1
  else if (TMyItem(Item2).NextStart = 0) and (TMyItem(Item1).NextStart = 0) then
    Result := 0 // Item2 = Item1
  else // ab hier ist keiner der beiden Werte 0
  if TMyItem(Item2).NextStart < TMyItem(Item1).NextStart then
    Result := -1 // Item2 < Item1
  else if TMyItem(Item2).NextStart > TMyItem(Item1).NextStart then
    Result := +1 // Item2 > Item1
  else
    Result := 0; // Item2 = Item1
end;
Hab's nicht ausprobiert, aber so müsste es eigentlich stimmen!

Christian Seehase 10. Feb 2009 21:21

Re: TObjectList - Sort crash (D7)
 
Moin Zusammen,

auch wenn der Ursprung des Threads schon recht alt ist, vielleicht liest es ja mal jemand, der ein Problem hat, wie der der TE.

Ich frage mich, warum die Methode MyNewItem als Funktion ausgeführt ist, da ja der Rückgabewert nicht verwendet wird.

So würde ich es mal probieren:

Delphi-Quellcode:
procedure TMyItemList.NewMyItem(a1,a2,a3:Integer);

var
  tmi : TMyItem;

begin
  tmi := TMyItem.Create(Self)
  tmi.V1 := a1;
  tmi.V2 := a2;
  tmi.V3 := a3;
  Self.Add(tmi);
end;

globetrotter77 10. Feb 2009 22:47

Re: TObjectList - Sort crash (D7)
 
Zitat:

Zitat von Christian Seehase
Ich frage mich, warum die Methode MyNewItem als Funktion ausgeführt ist, da ja der Rückgabewert nicht verwendet wird.

So würde ich es mal probieren:

Delphi-Quellcode:
procedure TMyItemList.NewMyItem(a1,a2,a3:Integer);
...

Genau das wollte ich eigentlich auch noch schreiben, hab's aber wohl wieder verdrängt.
Da könnte auch das Problem begraben sein, denn ich weiß nicht, ob man das Result einer Function ganz ohne Probleme innerhalb der eigenen Function so zuweisen kann.


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