[crossfire] safe/common item stack/inventory iteration?
Bernd Edler
edler at heydernet.de
Mon Jun 25 11:52:40 CDT 2007
On Sun, 24 Jun 2007, Mark Wedel wrote:
>
> Looking at a crash on metalforge, and it is in a loop like:
>
> for (tmp = op->inv; tmp != NULL; tmp = next) {
> next = tmp->below;
> { do some work }
> }
>
> Now this construct is used to cover the case where the current object (tmp)
> goes away - we have a pointer to the next object. Such operations are not that
> uncommon, as the {do some work} block is more likely to destroy tmp.
>
> However, in this case, it appears that next was destroyed, so after {do some
> work} completed, tmp became next, and next (tmp->below) pointed to garbage, so
> the iteration after that crashed.
...
> The easiest thing in this case is to probably store something
> like next_count, and see if that differs (suggesting the item was destroyed),
> and if so, just bail out of the loop.
>
If we are sure tmp will not be destroyed in some uncontrollable recursive
calls we can avoid bailing out altogether:
for (tmp = op->inv;tmp != NULL;;) {
destroy_me = NULL;
{
do some work
replace destroy_obj(tmp) with destroy_me = tmp;
do more work
}
tmp = tmp->below;
if { destroy_me } then destroy_obj(destroy_me);
}
If we want the big and clean solution, we only really kill objects
afterwards. This costs us one extra pointer per
object. like ob->destroy_list,
plus two variables: Destroy_list_first,Destroy_list_last
As in:
void mark_for_destruction(object ob) {
if ( ob->destroy_list != null ) then return;
/* this one is dead already */
if ( Destroy_list_first == NULL ) then {
Destroy_list_first = ob;
Destroy_list_last = ob;
}
Destroy_list_last->destroy_list = ob;
ob->destroy_list = ob;
/* self-reference marks end of list */
Destroy_list_last = ob;
{ remove the object from lists like active,below etc. }
}
void destroy_marked_objects() {
for (tmp = Destroy_list_first; tmp != NULL; tmp = next) {
next = tmp->destroy_list;
free(tmp);
/* the object should already be removed from all lists */
/* save this destruction list */
if (next == tmp) then last;
/* self-reference marks end of list *
}
Destroy_list_first = NULL;
Destroy_list_last = NULL;
}
More information about the crossfire
mailing list