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/)
-   -   Delphi Pointer-Problem (https://www.delphipraxis.net/166023-pointer-problem.html)

stahli 26. Jan 2012 11:21

Pointer-Problem
 
Hi,

ich nutze einige Objekte zur Datenverwaltung und lasse die in ggf. Listen sortieren.

Gestern bekam ich ein Problem, das ich mir nicht erklären kann. Eine Sortierfunktion knallt mir gelegentlich um die Ohren.

Nach einiger Suche fand ich heraus, dass die Pointer i.d.R. so um die $0800.0000 liegen. Gelegentlich ist dann einer über $1000.0000 dabei, was zu einer Zugriffsverletzung führt.

Also habe ich vor der Sortierung die Liste untersucht. Da ist aber noch alles i.O.!?

Natürlich kann ich nochmal alles neu aufbauen und z.B. eine generische Liste nutzen, aber irgendwie muss sich das Problem doch finden lassen.

Hat da jemand eine Idee?


Delphi-Quellcode:
function ListSortCompetitors(Item1, Item2: Pointer): Integer;
var
  C1, C2: TodCompetitor;
begin
  if Integer(Item1) >= $10000000 then
  begin
    Exit(0); // Zugriffsfehler vermeiden
  end;
  if Integer(Item2) >= $10000000 then
  begin
    Exit(0); // Zugriffsfehler vermeiden
  end;
  if TComponent(Item1).ClassName <> 'TodCompetitor' then
  begin
    beep;
  end;
  if TComponent(Item2).ClassName <> 'TodCompetitor' then
  begin
    beep;
  end;
  C1 := TodCompetitor(Item1);
  C2 := TodCompetitor(Item2);
  if C1.Tag <> C1.GameParty.Tag then
  begin
    beep;
  end;
  if C2.Tag <> C2.GameParty.Tag then
  begin
    beep;
  end;
  Result := CompareValue(C2.GameParty.PlayerList.Count, C1.GameParty.PlayerList.Count);
  if Result = 0 then
    Result := Random(3) - 1;
end;
 
//
 
...
// CL ist ein Container, der intern eine einfache Liste verwaltet
for I := 0 to CL.Count - 1 do // Liste vor Sort prüfen
  begin
    // CodeSite.Send(inttostr(CL.Competitor(I).GameParty.PlayerList.Count));
    if Integer(Pointer(CL.Competitor(I))) > $10000000 then
      begin
        beep; // kommt nicht vor
      end;
    if not odExist(CL.Competitor(I)) then
      begin
        beep; // kommt nicht vor
      end;
    if CL.Competitor(I).Tag <> Succ(I) then
      begin
        beep; // kommt nicht vor
      end;
    if not odExist(CL.Competitor(I).GameParty) then
      begin
        beep; // kommt nicht vor
      end;
    if CL.Competitor(I).GameParty.Tag <> Succ(I) then
      begin
        beep; // kommt nicht vor
      end;
  end;
if CL.Count > 1 then
  CL.Items.Sort(ListSortCompetitors); // Liste Sortieren - gelegentlich Zugriffsfehler
...

MacGuyver 26. Jan 2012 11:32

AW: Pointer-Problem
 
Moin,

du könntest da ein Problem im Sortieralgorythmus haben, weil sich die Datenmenge ändert:

Delphi-Quellcode:
Result := CompareValue(C2.GameParty.PlayerList.Count, C1.GameParty.PlayerList.Count);
   if Result = 0 then
     Result := Random(3) - 1;
Bei Gleichheit sortiert er mal so und mal so. Schaffe anders eine sichere Sortierfolge. Du könntest den Pointer auf Integer casten und damit bei Gleichheit vergleiche.

Stefan

stahli 26. Jan 2012 11:52

AW: Pointer-Problem
 
Das dachte ich auch schon, aber eine Sortierfunktion nur mit
Delphi-Quellcode:
Result := Random(3) - 1;
macht keine Probleme.

Ich dachte dann, dass u.U. vielleicht durch die Zufallswerte ein paar "unnötige Vergleiche" durchgeführt werden, was aber letztlich kein wirkliches Problem wäre.

Wenn ich die Pointer vergleiche, hätte ich ja eine feste Reihenfolge, was ich gerade vermeiden will.
Ich kann ja mal testweise in Tag einen Zufallswert schreiben und darauf vergleichen. Aber irgendwie komisch, das Ganze.

Wo dieser komische Pointer her kommt, ist mir halt unklar.

Ach so ... Ich weiß jetzt gar nicht, welches Sortierverfahren List.Sort nutzt (kann ich später erst nachschauen). Evtl. sind die Reihenfolgen bei 0 ja ohnehin undefiniert - dann könnte ich mir das ganze randomieren ;-) auch sparen.

p80286 26. Jan 2012 12:08

AW: Pointer-Problem
 
Versuch es doch mal so:
Delphi-Quellcode:
  C1 := TodCompetitor(Item1^);
  C2 := TodCompetitor(Item2^);
Gruß
K-H

himitsu 26. Jan 2012 12:25

AW: Pointer-Problem
 
Zitat:

Delphi-Quellcode:
  if Integer(Item1) >= $10000000 then
  begin
    Exit(0); // Zugriffsfehler vermeiden

Was für Zugriffsfehler sollen das denn sein?

In einem Win32-Programm kann ein Pointer locker bis $7FFFFFFF gehn und bei aktivierter 3 GB-Speicherverwaltung auch noch viel weiter hoch.

Bei dir müssen Pointer innerhalb der ersten 256 MB des virtuellen Arbeitsspeichers liegen, wo sie zu mindetens 88% ganz bestimmt nicht liegen werden. (bis zu durchschnittlich 94% bei 3-4 GB)

Blup 26. Jan 2012 15:31

AW: Pointer-Problem
 
Vorab wird CL.Competitor geprüft, sortiert wird aber CL.Items.
Stellt sich die Frage, was ist da überhaupt drin und wie kommt es da rein.

stahli 26. Jan 2012 20:09

AW: Pointer-Problem
 
Ok, gelöst: In der Sortfunktion mit Random zu arbeiten, ist offenbar keine gute Idee. Scheinbar haut das u.U. die Items etwas durcheinander.

Ich habe einfach mal dem Tag der Einträge einen Zufallswert zugewiesen und so funktioniert das sofort perfekt.
Delphi-Quellcode:
  if CL.Count > 1 then
    begin
      for I := 0 to CL.Count - 1 do
        CL.Competitor(I).Tag := Random($FFFF);
      CL.Items.Sort(ListSortCompetitors);
    end;
Auch Result immer 0 zuzuweisen führt zu einer gewissen zufälligen Sortierung. Allerdings sind davon nicht alle Einträge betroffen.


@Blup
CL.Competitor(I) castet letztlich CL.Items[I].
Ich kann leider nicht mit Generics arbeiten, da die RTTI mit generischen Klassen nicht ausreichend zurecht kommt und ích die Objekte serialisiere.

himitsu 26. Jan 2012 20:56

AW: Pointer-Problem
 
So, hier erstmal der Comparer mit einer ordentlichen Typkonvertierung
Delphi-Quellcode:
function ListSortCompetitors(Item1, Item2: Pointer): Integer;
var
  C1, C2: TodCompetitor;
begin
  C1 := TObject(Item1) as TodCompetitor;
  C2 := TObject(Item2) as TodCompetitor;
  Result := CompareValue(C2.GameParty.PlayerList.Count, C1.GameParty.PlayerList.Count);
  if Result = 0 then
    Result := Random(3) - 1;
end;
Delphi-Quellcode:
function ListSortCompetitors(Item1, Item2: Pointer): Integer;
begin
  Result := CompareValue((TObject(Item2) as TodCompetitor).GameParty.PlayerList.Count,
                         (TObject(Item1) as TodCompetitor).GameParty.PlayerList.Count);
  if Result = 0 then
    Result := Random(3) - 1;
end;
Ansonsten ist die Unterschreidung nach Speicheradresse kommplett falsch gedacht, denn die Verteilung im Speicher ist willkürlich und wie schon erwähnt, sind Werte über $10000000 vollkommen plausibel und definitiv kein Erkennungsmerkmal für einen "defekten" Pointer. (vorallem wenn dein Arbeitsspeicher mal etwas voller wird).

Wenn bei dieser Funktion Zeiger defekt sind, dann sind vermutlich die schon die Zeiger defekt, welche sich in deiner Liste befinden.

Liegt es nicht an der Liste liegt, dann könnte es höchstens noch daran liegen, daß deine Zufallswerte den Sortieralgo durchdrehen lassen und dieser z.B. über die Arraygrenzen seiner Liste hinausläuft.
Aber auch das dürfte nicht passieren und ich würde sowas dann eher als einen Bug im Sortieralgorithmus abstempeln.
(auch wenn es nicht so einfach ist, wenn man versucht sich ständig verändernde Werte zu sortieren, welche sich wärend des Sortierens verändern, ohne daß man sie vorher zwischenspeichert)

sx2008 26. Jan 2012 21:05

AW: Pointer-Problem
 
Ich habe jetzt öfters die Random() Funktion hier gesehen;
also wenn das Ziel sein sollte eine Liste durch Sortieren (Quicksort) in eine zufällige Reihenfolge zu bringen, dann ist ein suboptimaler Weg.
Dafür sollte man den Fisher-Yates Algorithmus verwenden.

stahli 26. Jan 2012 21:07

AW: Pointer-Problem
 
Den TypeCast hatte ich schon mit TComponent(Item1) versucht, was auch schon zu einem Fehler führte.

Offenbar toleriert die SortRoutine wirklich nicht die Zufallswert-Zuweisung und "dreht durch" bzw. schmeißt irgendwelche temporäre Adressen durcheinander (oder was auch immer). Auf jeden Fall ist vor Sort noch alles i.O. und während der Sortierung kracht es dann.
Ob man das als Bug bezeichnen muss, weiß ich nicht recht.

Ich wollte es mir möglichst einfach machen und gleichrangige Einträge nochmal verwürfeln.
Aber dann geht das halt auf dem Weg nicht (oder jedenfalls nicht zuverlässig).


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