www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Can remove AA elements during foreach?

reply Nick Sabalausky <SeeWebsiteToContactMe semitwist.com> writes:
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");
Feb 16 2013
next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
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
Feb 16 2013
parent Nick Sabalausky <SeeWebsiteToContactMe semitwist.com> writes:
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.
Feb 16 2013
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
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
Feb 16 2013