Thread overview | ||||||
---|---|---|---|---|---|---|
|
February 17, 2013 Can remove AA elements during foreach? | ||||
---|---|---|---|---|
| ||||
Is this both legal and safe?: foreach(key; assocArray) if(key != "foobar") assocArray.remove("foobar"); If not, then what about this?: foreach(key; assocArray.byKey()) if(key != "foobar") assocArray.remove("foobar"); |
February 17, 2013 Re: Can remove AA elements during foreach? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Nick Sabalausky | On Sat, Feb 16, 2013 at 06:59:59PM -0500, Nick Sabalausky wrote: > Is this both legal and safe?: > > foreach(key; assocArray) > if(key != "foobar") > assocArray.remove("foobar"); > > If not, then what about this?: > > foreach(key; assocArray.byKey()) > if(key != "foobar") > assocArray.remove("foobar"); Both are unsafe, because opApply, byKey, byValue, rely on a pointer to the current AA Slot and a pointer to the hash table to keep track of where they are. Modifying the AA while in the middle of doing this may cause strange effects, like the loop terminating prematurely, or traversing already-deleted items. Keep in mind that a rehash may occur during modification, so imagine what it will do if you're still iterating pointers to the original AA. For full fool-proofness, do this: auto keys = assocArray.keys; foreach (key; keys) doWhateverYouWantHere(key); T -- The fact that anyone still uses AOL shows that even the presence of options doesn't stop some people from picking the pessimal one. - Mike Ellis |
February 17, 2013 Re: Can remove AA elements during foreach? | ||||
---|---|---|---|---|
| ||||
Posted in reply to H. S. Teoh | On Sat, 16 Feb 2013 16:20:30 -0800
"H. S. Teoh" <hsteoh@quickfur.ath.cx> wrote:
> On Sat, Feb 16, 2013 at 06:59:59PM -0500, Nick Sabalausky wrote:
> > Is this both legal and safe?:
> >
> > foreach(key; assocArray)
> > if(key != "foobar")
> > assocArray.remove("foobar");
> >
> > If not, then what about this?:
> >
> > foreach(key; assocArray.byKey())
> > if(key != "foobar")
> > assocArray.remove("foobar");
>
> Both are unsafe, because opApply, byKey, byValue, rely on a pointer to the current AA Slot and a pointer to the hash table to keep track of where they are. Modifying the AA while in the middle of doing this may cause strange effects, like the loop terminating prematurely, or traversing already-deleted items. Keep in mind that a rehash may occur during modification, so imagine what it will do if you're still iterating pointers to the original AA.
>
> For full fool-proofness, do this:
>
> auto keys = assocArray.keys;
> foreach (key; keys)
> doWhateverYouWantHere(key);
>
Yea, that's the fallback I was using. Not that it's critical, but I was hoping there'd be a simple way to do it without a dynamic allocation.
|
February 17, 2013 Re: Can remove AA elements during foreach? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Nick Sabalausky | On Sat, 16 Feb 2013 18:59:59 -0500, Nick Sabalausky <SeeWebsiteToContactMe@semitwist.com> wrote: > Is this both legal and safe?: > > foreach(key; assocArray) > if(key != "foobar") > assocArray.remove("foobar"); > > If not, then what about this?: > > foreach(key; assocArray.byKey()) > if(key != "foobar") > assocArray.remove("foobar"); > Both are unsafe. Note that with Dcollections, there is a special purge feature that allows safe removal while traversing: foreach(ref doPurge, key, value; &hashMap.purge) doPurge = (key != "foobar"); All dcollections' classes support this. There is a keys collection, but that does not support purge. I can actually add it pretty easily though... -Steve |
Copyright © 1999-2021 by the D Language Foundation