It's odd that it's still so restrictive, because I looked into this pretty carefully and found that although insertion in the middle of an each loop can (and does) cause big problems, there is no way that deletion can cause trouble.

This is for two reasons. First, unlike insertion, a deletion never causes a complete reorganization of the entire hash. (This is mentioned in the part of the FAQ that you quoted.) But there's also something more subtle going on.

The way a hash works is that it's a collection of lists of he items. Each he has a pointer to a key, to the associated value, and a pointer to the next he in the list. Every hash also keeps track of the 'current' he. When you call each, it advances the 'current item' pointer to the next he. It can do this because each he points at the next one.

Normally, when you call delete, the memory for the deleted he is reclaimed right away. But if you delete the 'current item', there's a complication. If the he were destroyed and the memory were reclaimed right away, then the next time you called each, it wouldn't work, because it needs to find the 'next' item, and the information would have been stored in the he that you destroyed.

So there is special-case code inside the delete function that specifically checks to see if you are deleting the 'current item', and if so, it postpones the destruction of the he until after the next time you call each. There's more special-case code inside of each that checks to see if you already used delete on the current item, and if so, it belatedly destroys the he after advancing the 'current item'.

In other words, Larry went to some special effort to make sure that you could delete nodes inside of an each loop, so it's particularly odd that this isn't documented.

In recognition of this, the Perl 5.6.1 the manual will include the following:

Exception: It is always safe to delete the item most recently returned by each(), which means that the following code will work:
while (($key, $value) = each %hash) { print $key, "\n"; delete $hash{$key}; # This is safe }
But I still don't know why arbitrary deletions are warned against, since they do always work.


In reply to Re: Adding or removing keys while iterating over a hash by Dominus
in thread Adding or removing keys while iterating over a hash by mischief

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.