shemp has asked for the wisdom of the Perl Monks concerning the following question:

Hi all, I have been a bit stumped about something for a while. Often in scripts, i'll have large hashrefs or arrayrefs, and pass them around as refs, to avoid memory consumption. But there are some things i end up doing with them, where i can never tell if im making deep copies or not. (i want to avoid this usually, for memory issues).
Take the following code for instance:
sub get_big_arrayref { # blah blah blah return \@big_array; } { ... my $big_arrayref = get_big_arrayref(); foreach my $value (@$big_arrayref) { # whatever } }
Now my concern is that when writing @$big_arrayref, that dereferences the array, and makes a copy. In and of itself, foreach() hasnt made a copy since old versions of perl, but that deref will.
I can get around the problem here with:
for my $i (0 .. $#$big_arrayref) {
Or at least i think this doesnt do any sublte dereferencing.

But, what happens when i have a big hashref. To use any of the hash traversal built-in functions, such as each, key, values, etc, the arguement must be a hash, not a hashref. So again, the big ref is dereferenced with something like:
while ( my($key, $value) = each %$big_hashrerf ) {
And i dont see any way around this problem.

So, what i'm looking for: Thanks much for any insight, i hope im not too far off base.

Replies are listed 'Best First'.
Re: Dereferencing woes
by davido (Cardinal) on May 05, 2004 at 19:20 UTC
    You don't get a copy when you dereference an array ref. But perhaps you're thinking of the anonymous array constructor, which will create a copy.

    For example:

    my @array = ( 1, 2, 3 ); my $aref = \@array;

    The above example doesn't create a copy of @array. But the following will:

    my @array = ( 1, 2, 3 ); my $aref = [ @array ];

    This may be desirable behavior. There are times, for example, where you really do need a copy to be made so that you're pointing to a new array rather than to the old one.

    Another construct to consider when using hashes is using keys in list context. For example:

    foreach my $key ( keys %hash ) { ........ }

    IIRC, keys in list context will create a list of the keys, which means that in addition to your hash, you've also got in memory a temporary list of its keys; that could be a memory hog. If that's a concern, use the while ( my( $key, $val ) = each %hash ) { ........ } construct, since this shouldn't cause a list to be generated.

    So as the previous followup suggest, don't worry about it, it's not creating a copy.

    You do have to be concerned with things like sort though. Even if you're saying @array = sort @array sort is probably creating a temporary list somewhere to assign to @array. The assignment is done in one fell swoop, so the entire list must be created first.


    Dave

      Even if you're saying @array = sort @array sort is probably creating a temporary list somewhere to assign to @array.
      From Perl 5.8.4 onwards, that particular construct is optimised to sort the array in-place, so no copying is done.
Re: Dereferencing woes
by japhy (Canon) on May 05, 2004 at 18:55 UTC
    Rest easy: you're wrong. There is no copy being made.

    Update: what the dereferencing is doing is just telling Perl to use the data structure stored in the reference. It's not copying it anywhere.

    _____________________________________________________
    Jeff[japhy]Pinyan: Perl, regex, and perl hacker, who'd like a job (NYC-area)
    s++=END;++y(;-P)}y js++=;shajsj<++y(p-q)}?print:??;