Документация
HTML CSS PHP PERL другое

Section 5.3.  Reference Counting and Nested Data Structures

 
Previous
Table of Contents
Next

5.3. Reference Counting and Nested Data Structures

The data remains alive until we destroy the last reference, even if that reference lives within a larger active data structure. Suppose an array element is itself a reference. Recall the example from Chapter 4:

my @skipper = qw(blue_shirt hat jacket preserver sunscreen);
my @skipper_with_name   = ('The Skipper', \@skipper);

my @professor = qw(sunscreen water_bottle slide_rule batteries radio);
my @professor_with_name = ('The Professor', \@professor);

my @gilligan = qw(red_shirt hat lucky_socks water_bottle);
my @gilligan_with_name  = ('Gilligan', \@gilligan);

my @all_with_names = (
        \@skipper_with_name,
        \@professor_with_name,
        \@gilligan_with_name,
        );

Imagine for a moment that the intermediate variables are all part of a subroutine:

my @all_with_names;

sub initialize_provisions_list {
  my @skipper = qw(blue_shirt hat jacket preserver sunscreen);
  my @skipper_with_name = ('The Skipper', \@skipper);

       my @professor = qw(sunscreen water_bottle slide_rule batteries radio);
  my @professor_with_name = ('The Professor', \@professor);

  my @gilligan = qw(red_shirt hat lucky_socks water_bottle);
  my @gilligan_with_name = ('Gilligan', \@gilligan);

  @all_with_names = ( # set global
    \@skipper_with_name,
    \@professor_with_name,
    \@gilligan_with_name,
  );
}

initialize_provisions_list(  );

We set the value of @all_with_names to contain three references. Inside the subroutine we have named arrays with references to arrays first placed into other named arrays. Eventually, the values end up in the global @all_with_names. However, as the subroutine returns, the names for the six arrays disappear. Each array has had one other reference taken to it, making the reference count temporarily two, and then back to one as the name disappears. Because the reference count is not yet zero, the data continues to live on, although it is now referenced only by elements of @all_with_names.

Rather than assign the global variable, we can rewrite this without @all_with_names and return the list directly:

sub get_provisions_list {
  my @skipper = qw(blue_shirt hat jacket preserver sunscreen);
  my @skipper_with_name = ('The Skipper', \@skipper);

  my @professor = qw(sunscreen water_bottle slide_rule batteries radio);
  my @professor_with_name = ('The Professor', \@professor);

  my @gilligan = qw(red_shirt hat lucky_socks water_bottle);
  my @gilligan_with_name = ('Gilligan', \@gilligan);

  return (
    \@skipper_with_name,
    \@professor_with_name,
    \@gilligan_with_name,
  );
}

my @all_with_names = get_provisions_list(  );

Here, we create the value that we'll eventually store in @all_with_names as the last expression evaluated in the subroutine. The subroutine returns a three-element list. As long as the named arrays within the subroutine have had at least one reference taken of them, and it is still part of the return value, the data remains alive.[*] If we alter or discard the references in @all_with_names, Perl reduces the reference count for the corresponding arrays. If that means the reference count has become zero (as in this example), Perl also eliminates the arrays themselves. Because the arrays inside @all_with_names also contain a reference (such as the reference to @skipper), Perl reduces that reference count by one. Again, that reduces the reference count to zero, freeing that memory as well, in a cascading effect.

[*] Compare this with having to return an array from a C function. We must either return a pointer to a static memory space, making the subroutine nonreentrant, or we must malloc new memory space, requiring the caller to know to free the data. Perl just does the right thing.

Removing the top of a tree of data generally removes all the data contained within. The exception is when we make additional copies of the references of the nested data. For example, if we copy Gilligan's provisions:

my $gilligan_stuff = $all_with_names[2][1];

then when we remove @all_with_names, we still have one live reference to what was formerly @gilligan, and the data from there downward remain alive.

The bottom line is simply: Perl does the right thing. If we still have a reference to data, we still have the data.


Previous
Table of Contents
Next
© 2000- NIV