PushListPosition()/PopListPosition() unerwartetes Verhalten

Hier werden, insbesondere in den Beta-Phasen, Bugmeldungen gepostet. Das offizielle BugForum ist allerdings hier.
Benutzeravatar
cxAlex
Beiträge: 2111
Registriert: 26.06.2008 10:42

PushListPosition()/PopListPosition() unerwartetes Verhalten

Beitrag von cxAlex »

Servus.

Ich bin mir jetzt nicht sicher ob man das als 'reinen' Bug sehen kann da der Debugger ja eigentlich warnt, aber das Verhalten ist doch unerwartet:

Ich iteriere durch alle Elemente einer Liste und in dieser Iteration muss ich nochmal durch alle Elemente iterieren (ein Element gegen alle anderen vergleichen), also ein ideales Einsatzgebiet für Push/Pop - ListPosition. Nun werden in der inneren Iteration einige Elemente der Liste gelöscht, und es kann auch vorkommen das dass Element gelöscht wird auf das PopListPosition() angewant wurde. Nun meckert der Debugger das auch an (wobei ich den nicht nutzen konnte da das Ganze in eine DLL steckt die selbst nicht lauffähig ist.), und es ist ja nicht so schwer das anders zu programmieren, wie inzwischen auch geschehen. ABER, jetzt der Teil der mich stört: ohne Debugger kompiliert steht nach dem PopListPosition() das gelöschte Element als aktuelles Element wieder zur Verfügung, OHNE irgend einen illegalen Speicherzugriff zu verursachen (liegt wohl daran dass das Element nicht gelöscht wird da die PB - Listen Elemente "geblock" alloziert werden). Fügt man nun Elemente hinzu, resultiert das Ergebnis (je nach den folgenden Listen - Befehlen, unterschiedlich) entweder in einer Endlos - Liste die nur aus den neuen Elementen besteht oder in einer korrekten Version der alten List (wo allerdings die neuen Fehlen). Also, will sagen: Der Fehler liegt darin das PoplistPosition() oder DeleteElement() sich nicht so verhalten wie erwartet (irgend einen Speicher-Fehler, btw. DeleteElement() könnte auf das Previous-Element zurückfallen wenn ein PushListPosition() Element gelöscht wird, wenn es möglich ist das zu detektieren (was ja bereits gemacht wird), sollte es auch möglich sein den "gepopten" Wert durch den Previous-Wert oder 0 zu ersetzen, also das nach PopListPosition() das erwartete Ergebniss nach einem Delete() vorliegt.)

Code: Alles auswählen

EnableExplicit

NewList t()

; Testdaten:
AddElement(t()) : t() = 1
AddElement(t()) : t() = 2
AddElement(t()) : t() = 3
AddElement(t()) : t() = 0

; Code ist in einer DLL, also die einzig  möglichen Debug Ausgaben sind via MessageRequester()
DisableDebugger

; Alle Elemente aus t() löschen die gleich 0 sind
PushListPosition(t())
ForEach t()
  If Not t()
    DeleteElement(t())
  EndIf
Next
PopListPosition(t())

EnableDebugger

AddElement(t()) : t() = 4
AddElement(t()) : t() = 5
AddElement(t()) : t() = 6

If #True ; Change to see the Result
  Repeat 
    Debug t()
  Until Not PreviousElement(t())
Else
  ForEach t()
    Debug t()
  Next
EndIf
Projekte: IO.pbi, vcpu
Pausierte Projekte: Easy Network Manager, µC Emulator
Aufgegebene Projekte: ECluster

Bild

PB 5.1 x64/x86; OS: Win7 x64/Ubuntu 10.x x86
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7031
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: PushListPosition()/PopListPosition() unerwartetes Verhal

Beitrag von STARGÅTE »

Vorab: DeleteElement() löscht nicht das Element an sich (leer also nicht den Datenspeicher) sondern löscht nur die Verweise beim Vorgänger und Nachfolger auf dieses Element.
Deswegen sind Element durchaus noch gültig (speichermäßig) nachdem DeleteElement() ausgeführt wurde.

Normalerweise kommt es aber nie dazu das du ein gepushes Element löschen musst, wenn du den Vergleich "richtig" machst, wie es u.a. auch in der Hilfe gezeigt wird.
Du musst ja garnicht die innere Schleife auch von Anfang bis Ende durchgehen, sondern nur ab dem nächsten Element.
Bei 1,2,3 reicht ja der Vergleich zwischen: 1-2, 1-3, 2-3. 1-1, 2-2 und 3-3 zu vergleichen ist unnötig, und 2-1, 3-1, 3-2 wurden beteits vorher verglichen.
Dann löschst du ggf. auch nur Elemente die noch nicht gepushed wurden.

Edit: Ein Bug ist es definitiv nicht, denn du wirst eindeutig vom Debugger gewarnt!
Das wäre das gleiche, wenn du die Adresse eines Elements speicherst, es dann löschst, und dann mit ChangeCurrentElement() darauf zugreifst.
Du kannst von DeleteElement() auch nicht erwarten, dass es den PushStack durchläuft, um zu gucken, ob das Element ggf. gepushed wurde, dass würde die Funktion nur unnötig langsam machen.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Benutzeravatar
cxAlex
Beiträge: 2111
Registriert: 26.06.2008 10:42

Re: PushListPosition()/PopListPosition() unerwartetes Verhal

Beitrag von cxAlex »

Der Code soll nur den Effekt demonstrieren, im Orginal ist es nötig jedesmal alle Elemente zu vergleichen, da die Elemente nicht nur gelöscht, sondern auch auch verändert werden können (eine strukturierte Liste), was bei einem Späteren das Ergebnis ändert. Auch ist es relevant ob 1 gegen 3 oder 3 gegen 1 verglichen wird (1-3) (3-1), das Ergibt in meinem Fall nicht dasselbe. (3-3 ist in dem Fall auch nicht sinnfrei da es im Orginal komplexer ist: Jedes Element von ParentList() enthält 2 Child-Listen und jedes Element von ChildList1() jedes Elements von ParentList() gegen jedes Element von ChildList2() jedes Elements von ParentList() geprüft werden muss. Sogar der Satz ist kompliziert ... :freak: )

Wie gesagt, es ist jetzt auch schon intern anders gelöst, allerdings ist das Verhalten dieser Befehle nicht gerade hilfreich.
Du kannst von DeleteElement() auch nicht erwarten, dass es den PushStack durchläuft, um zu gucken, ob das Element ggf. gepushed wurde, dass würde die Funktion nur unnötig langsam machen.
Das macht es aber bereits da es das löschen jedes Elements von PushStack erkennt, es ist also bereits implementiert!
Projekte: IO.pbi, vcpu
Pausierte Projekte: Easy Network Manager, µC Emulator
Aufgegebene Projekte: ECluster

Bild

PB 5.1 x64/x86; OS: Win7 x64/Ubuntu 10.x x86
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7031
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: PushListPosition()/PopListPosition() unerwartetes Verhal

Beitrag von STARGÅTE »

cxAlex hat geschrieben:Das macht es aber bereits da es das löschen jedes Elements von PushStack erkennt, es ist also bereits implementiert!
Ja natürlich, aber nur im Debug-Modus.
Aber es wäre schlimm, wenn es auch mit kompiliert werden würde.

Eine Möglichkeit wäre halt einen zusätzlichen Flag für DeleteElement einzubauen, der genau diese Überprüfung dann auch in der EXE/DLL durchführt. Das gibt es ja auch bei AddMapElement(), um die Funktion zu beschleunigen.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Benutzeravatar
cxAlex
Beiträge: 2111
Registriert: 26.06.2008 10:42

Re: PushListPosition()/PopListPosition() unerwartetes Verhal

Beitrag von cxAlex »

Stimmt, so ein Flag wäre eine akzeptable Lösung und sollte auch nicht zu schwer zu realisieren sein da der Abfrage - Mechanismus ja bereits besteht.
Projekte: IO.pbi, vcpu
Pausierte Projekte: Easy Network Manager, µC Emulator
Aufgegebene Projekte: ECluster

Bild

PB 5.1 x64/x86; OS: Win7 x64/Ubuntu 10.x x86
Antworten