Check if ChangeCurrentElement() returns a valid element
Check if ChangeCurrentElement() returns a valid element
Hi,
A simple question : how do I check if the pointer in ChangeCurrentElement() "points" to a valid element in the list ? I'm in a program in which I sometimes delete the pointed element before calling ChangeCurrentElement(). Therefore the current element becomes the first one.
Thanks.
A simple question : how do I check if the pointer in ChangeCurrentElement() "points" to a valid element in the list ? I'm in a program in which I sometimes delete the pointed element before calling ChangeCurrentElement(). Therefore the current element becomes the first one.
Thanks.
Re: Check if ChangeCurrentElement() returns a valid element
ListIndex() will return -1 if the list pointer does not point at a valid element. You could use that?
Re: Check if ChangeCurrentElement() returns a valid element
No.
If the pointer is invalid ChangeCurrentElement() or an other list-function generates a IMA.
You have to check it self, if the pointer is valid before you call this function.
If the pointer is invalid ChangeCurrentElement() or an other list-function generates a IMA.
You have to check it self, if the pointer is valid before you call this function.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Lizard - Script language for symbolic calculations and more ― Typeface - Sprite-based font include/module
Lizard - Script language for symbolic calculations and more ― Typeface - Sprite-based font include/module
Re: Check if ChangeCurrentElement() returns a valid element
Well, that's the question
How do you check if the pointer is valid ?
IMA ? When the pointer is invalid, ChangeCurrentElement() is like a FirstElement().
IMA ? When the pointer is invalid, ChangeCurrentElement() is like a FirstElement().
Re: Check if ChangeCurrentElement() returns a valid element
How do you check any other pointer ?Joubarbe wrote:Well, that's the questionHow do you check if the pointer is valid ?
If you allocate an object and the allocation is successful you get a valid pointer (<> 0).
Until you free the object, the pointer is valid.
If you free the object, you know the pointer you have it's not valid anymore.
Then you know it, if you forgot about it than it means you need to revise the logic you are using, or you need to track the pointers you are saving and possibly to mark your pointer as invalid (or removing it altogether) when deleting the pointed element.Joubarbe wrote: I sometimes delete the pointed element before calling ChangeCurrentElement()
"Have you tried turning it off and on again ?"
Re: Check if ChangeCurrentElement() returns a valid element
ChangeCurrentElement() is same like "CurrentElement() = *Pointer", with out checking.Joubarbe wrote:Well, that's the questionHow do you check if the pointer is valid ?
IMA ? When the pointer is invalid, ChangeCurrentElement() is like a FirstElement().
The only way to check you question:
Code: Select all
Foreach Element()
If *Piointer = @Element()
; Pointer is valid
EndIf
Next
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Lizard - Script language for symbolic calculations and more ― Typeface - Sprite-based font include/module
Lizard - Script language for symbolic calculations and more ― Typeface - Sprite-based font include/module
Re: Check if ChangeCurrentElement() returns a valid element
No, doesn't look that way (would be a very bad choice anyway). Why do you say that ?Joubarbe wrote: IMA ? When the pointer is invalid, ChangeCurrentElement() is like a FirstElement().
Code: Select all
NewList lst.i()
For k = 1 To 10
AddElement(lst())
lst() = k
If k = 5
*ptr = @lst() ; save ptr to fifth
EndIf
Next
ResetList(lst())
While NextElement(lst())
Debug lst()
Wend
ChangeCurrentElement(lst(), *ptr) ; jump to fifth
Debug lst() ; the fifth
DeleteElement(lst()) ; delete the fifth
Debug lst() ; the previous one is now the current, the fourth
ChangeCurrentElement(lst(), *ptr) ; jump to the old fifth
Debug lst() ; can be still there in memory an print "5" since only logically deleted and not physically, can cause an IMA, can print a different element, etc.
ChangeCurrentElement(lst(), *ptr + 32768) ; likely causing an IMA, probably out of the page size used internally by the list
Debug lst()
Also when you delete an element what happens right now (again you can't count on it) is its address is reused when adding a new element, so you would have your original pointer pointing to an element formally valid but still not the same you were originally pointing to.
Code: Select all
NewList lst.i()
For k = 1 To 10
AddElement(lst())
lst() = k
Debug Str(k) + "->" + @lst()
If k = 5
*ptr = @lst() ; save ptr to fifth
EndIf
Next
ChangeCurrentElement(lst(), *ptr) ; jump to fifth
DeleteElement(lst()) ; delete the fifth
For k = 11 To 15
AddElement(lst())
lst() = k
Debug Str(k) + "->" + @lst()
Next
ChangeCurrentElement(lst(), *ptr) ; jump to the old fifth
Debug lst()
If you really want you can mimic the IsImage(), IsFile(), etc. family of functions using a map with the pointers addresses adding and removing pointers as needed to be able to test for their validity by testing their presence in the map.
"Have you tried turning it off and on again ?"
Re: Check if ChangeCurrentElement() returns a valid element
Thanks Stargate.
I did not think of this obvious solution ( If *Pointer = @Element() ) for testing after a ChangeCurrentElement(Element(),*Pointer)
But it seems it does not work.
It's better using the classical ErrorHandler() to detect the error when the .exe is running.
I did not think of this obvious solution ( If *Pointer = @Element() ) for testing after a ChangeCurrentElement(Element(),*Pointer)
But it seems it does not work.
It's better using the classical ErrorHandler() to detect the error when the .exe is running.
PureBasic 6.20 beta 2 (x64) | Windows 10 Pro x64 | Intel(R) Core(TM) i7-8700 CPU @ 3.20Ghz 16 GB RAM, SSD 500 GB, PC locally assembled.
Come back to 6.11 LTS 64 bits because of an issue with #PB_ComboBox_UpperCase in ComboBoxGadget() (Oct. 10, 2024).
Come back to 6.11 LTS 64 bits because of an issue with #PB_ComboBox_UpperCase in ComboBoxGadget() (Oct. 10, 2024).
Re: Check if ChangeCurrentElement() returns a valid element
I would think a better solution than checking a pointer against possibly every list element's address would be to implement a custom process around each DeleteListElement().
The process would check the address of the element being deleted against the pointer. If there is a match it would either prevent the deletion or set the pointer to null.
Maybe something like this:
or this:
Both would be used:
For completeness something that also resets the pointer for other mass-delete operations would also be needed, such as for ClearList() or ResetList().
The process would check the address of the element being deleted against the pointer. If there is a match it would either prevent the deletion or set the pointer to null.
Maybe something like this:
Code: Select all
;set pointer to #Null if element is deleted
Macro _DeleteElement(ourList, ourPointer, flags = 0)
If @ourList = ourPointer
ourPointer = #Null
EndIf
DeleteElement(ourList, flags)
EndMacro
;wrap ChangeCurrentElement() to ensure pointer address is not #Null
;If *ptr
; ChangeCurrentElement(lst(), *ptr) ; jump to element if it exists, else no change
;EndIf
Code: Select all
;only delete if not being pointed to
Macro _DeleteElement(ourList, ourPointer, flags = 0)
If @ourList <> ourPointer
DeleteElement(ourList, flags)
EndIf
EndMacro
Code: Select all
_DeleteElement(theList(), *ptr)
;or
_DeleteElement(theList(), *ptr, 1) Re: Check if ChangeCurrentElement() returns a valid element
It seems that DeleteElement () remove the element from the list, but not for direct access with ChangeCurrentElement ().
You still get the value stored in the deleted element after a ChangeCurrentElement () to this deleted element.
But if you try to delete the same element a second time, there is a fatal error. Without ErrorHandler(), the .exe stops without any error message.
May be my code is wrong, but I don't see where...
You still get the value stored in the deleted element after a ChangeCurrentElement () to this deleted element.
But if you try to delete the same element a second time, there is a fatal error. Without ErrorHandler(), the .exe stops without any error message.
May be my code is wrong, but I don't see where...
Code: Select all
EnableExplicit
Global NewList Gl$()
Structure Sadr
*adr
EndStructure
Global NewMap Gm.Sadr()
Procedure addelem(P1$)
AddElement(gl$())
gl$() = P1$
AddMapElement(Gm(),gl$())
gm()\adr = @gl$()
Debug "@gl$(" + P1$ + ")=" + Str(@gl$())
EndProcedure
addelem("1")
addelem("2")
addelem("3")
ChangeCurrentElement(gl$(),gm("2")\adr)
DeleteElement(gl$())
Debug "-------------- list begin"
ResetList(gl$())
While NextElement(gl$())
Debug gl$()
Wend
Debug "-------------- list end"
ChangeCurrentElement(gl$(),gm("2")\adr)
If @gl$() <> gm("2")\adr
Debug "@gl$() <> gm('2')\adr"
Else
Debug "@gl$() = gm('2')\adr"
EndIf
Debug Str(@gl$()) + " compared to " + Str(gm("2")\adr)
If gl$() = "2"
Debug "gl$() = '2' just before the second DeleteElement(gl$())"
DeleteElement(gl$())
Else
Debug "gl$() <> '2'"
EndIf
PureBasic 6.20 beta 2 (x64) | Windows 10 Pro x64 | Intel(R) Core(TM) i7-8700 CPU @ 3.20Ghz 16 GB RAM, SSD 500 GB, PC locally assembled.
Come back to 6.11 LTS 64 bits because of an issue with #PB_ComboBox_UpperCase in ComboBoxGadget() (Oct. 10, 2024).
Come back to 6.11 LTS 64 bits because of an issue with #PB_ComboBox_UpperCase in ComboBoxGadget() (Oct. 10, 2024).
Re: Check if ChangeCurrentElement() returns a valid element
In your example, you just got lucky because the element was not freed yet due to the internal list memory management. If you start deleting more elements, the memory will really be released and you will get an access violation. You cannot rely on this.CONVERT wrote:It seems that DeleteElement () remove the element from the list, but not for direct access with ChangeCurrentElement ().
You can never reliably verify if an unknown pointer is a valid list element, because list elements get re-used after deletion. You can see that in this simple example:
Code: Select all
NewList a()
For i = 1 To 5
AddElement(a())
a() = i
Next i
FirstElement(a())
*Ptr = @a()
Debug @a()
Debug a()
DeleteElement(a())
AddElement(a())
a() = 42
Debug @a()
Debug a()
ChangeCurrentElement(a(), *Ptr)
Debug @a()
Debug a()This is why you have to take care yourself that you do not keep any pointers to elements that you delete. Such pointers become garbage.
quidquid Latine dictum sit altum videtur
Re: Check if ChangeCurrentElement() returns a valid element
Thanks a lot for your explanation and your example. Very interesting.
I agree with you, of course. It is very important to delete the pointer when the element is deleted.
I begin understanding why there is no return error on a ChangeCurrentElement().
I agree with you, of course. It is very important to delete the pointer when the element is deleted.
I begin understanding why there is no return error on a ChangeCurrentElement().
PureBasic 6.20 beta 2 (x64) | Windows 10 Pro x64 | Intel(R) Core(TM) i7-8700 CPU @ 3.20Ghz 16 GB RAM, SSD 500 GB, PC locally assembled.
Come back to 6.11 LTS 64 bits because of an issue with #PB_ComboBox_UpperCase in ComboBoxGadget() (Oct. 10, 2024).
Come back to 6.11 LTS 64 bits because of an issue with #PB_ComboBox_UpperCase in ComboBoxGadget() (Oct. 10, 2024).



