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

Hi Monks,

I am little curious, below is the code sample I was trying ...

@arr=(1,2,3); $arr_r=\@arr; print("accessing ref: @{$arr_r}\n"); print("referrence looks like: $arr_r\n"); undef @arr; print("accessing ref 2nd time: @{$arr_r}\n"); print("referrence now looks like: $arr_r\n");

the output I got ... like accessing ref: 1 2 3 referrence looks like: ARRAY(0x18305fc) accessing ref 2nd time: referrence now looks like: ARRAY(0x18305fc)

first time it's able to access the data but after undef'd it's not able to which is correct .... but the referrence still exist ... as you can see.

Is it same as "Dangling Pointer" in C???

Thanks

Replies are listed 'Best First'.
Re: Dangling Pointer::perl referrence
by ikegami (Patriarch) on Feb 17, 2010 at 22:21 UTC

    but the referrence still exist

    Of course. You never changed $arr_r.

    Is it same as "Dangling Pointer" in C???

    No. A dangling pointer is a pointer to something that doesn't exist anymore. You didn't even try to get rid of the array — undef simply empties it — so there's definitely no dangling pointer.

    Even if you tried to get rid of the array (like in the following example), you wouldn't get a dangling. The reference would keep it alive until you got rid of the reference too.

    my $ref; { my @array = 'element'; $ref = \@array; } # Because the array is lexically scoped (my), # the array would normally be freed here*, # but the reference is keeping it alive. print "$ref->[0]\n"; # Prints 'element' $ref = undef; # The scalar stops referencing the array, # so it's freed here.

    Think of my as new.

    my @outer; for (1..2) { my @inner = "pass $_"; push @outer, \@inner; } print "@{ $outer[0] }\n"; # pass 1 print "@{ $outer[1] }\n"; # pass 2

    But realize that Perl will get rid of something automatically as soon as noone needs it anymore. For example, if that entire piece of code was in a sub, @outer and the two @inner would get freed by the subroutine exit code*.

    One catch: Perl sometimes doesn't realize nothing needs a value anymore. It occurs when you have a reference cycle like the following:

    for (1..10) { my $r1; my $r2 = \$r1; my $r3 = \$r2; $r1 = \$r3; } # You have just leaked 30 variables.

    * — Aside from optimisations that would only confuse the issue.

      Hi ikegami,

      Thanks for your reply. From the example you given, it means that the referrence will keep the array alive unless I destroy the referrence too (as below)

      my $ref; { my @array = 'element'; $ref = \@array; }
      But what if I use like below
      { my @array = 'element'; } $ref = \@array; print "$ref\n";

      OR

      $ref=\@arr; #### @arr doesn't excist at all print "$ref\n";
      In both this case I get a output like below

      ARRAY(0x1830614)

      Now where it's referring too? There is no such variable ... means no such memory location?

      Thanks

        { my @array = 'element'; } $ref = \@array; print "$ref\n";

        That doesn't compile, at least not under use strict; which you should be using. The reason is the second @array is a completely different variable than the first. It's package variable $main::array, aka a global variable. Global variables, by definition and by design, don't get freed before the program exits (without taking some intentional action to remove it from the symbol table). Think of extern int a; in a .h.

        Now where it's referring too? There is no such variable ... means no such memory location?

        Global variables get created simply by using them. By taking a reference to previously non-existant @main::array (2nd snippet) or @main::arr (3rd snippet), they get created. Well, technically, they already existed in those snippets because the parser created them when it noticed they will be used. The following code peeks at the symbol table where package variables reside:

        >perl -E"say *array{ARRAY}||0;" 0 >perl -E"say *array{ARRAY}||0; @array; say *array{ARRAY}||0;" ARRAY(0x182a24c) ARRAY(0x182a24c) >perl -E"say *array{ARRAY}||0; @{'array'}; say *array{ARRAY}||0;" 0 ARRAY(0x238b24)

        The parser created @main::array when it compiled @array
        The runtime created @main::array when it evaluated @{"array"}

        Different to C there are global variables that spring into existence the moment you refer to them. So when perl executes $ref = \@array; in your second example, @array is a new global (but empty) variable that has nothing in common with the 'my @array' variable except for the name.

        If you had a line 'use warnings;' at the beginning of your script (a practice very recommended), you would have seen the following warning: "Name "main::array" used only once: possible typo at ./t7.pl line 6". Ok, not that easy to decipher, but once you know that global variables are living in name spaces, the default one being called 'main::', you would have a clue about what went wrong

        If you also had a line 'use strict;' at the beginning of your script (a practice very recommended for any script larger than a few lines) your script would have aborted at the compilation stage with error messages about global variables.

Re: Dangling Pointer::perl referrence
by Xiong (Hermit) on Feb 18, 2010 at 10:35 UTC

    No, it's not a dangling pointer. I'm not entirely sure references (pointers) can be made to dangle in Perl; I suppose it could be done if someone wanted to try hard enough. But Perl has automatic garbage collection.

    This little demo might prove interesting:

    no strict; # just for this demo use warnings; my $ref = \do{ my $anon = 42 }; my $deref = ${ $ref }; print '$ref: ' , "$ref\n"; print '$deref: ' , "$deref\n"; print '$anon: ' , "$anon\n"; __END__ Output: Name "main::anon" used only once: possible typo at ./anon-scalar-ref-d +emo.pl line 9. $ref: SCALAR(0x9dbefd8) $deref: 42 Use of uninitialized value $anon in concatenation (.) or string at ./a +non-scalar-ref-demo.pl line 9. $anon:

    Explanation:

    • Line 4 creates a variable, $anon, which is undefined at the outset, associates it with a memory location, and immediately puts 42 into that memory location. This assignment is enclosed in a do-block; so the variable goes out of scope almost as soon as it's created. However, do{} gets to act before that destruction and evaluates to the contents of the block: the variable that's about to be destroyed. The backslash takes a reference to that memory location and the variable name is destroyed. Finally, that reference is assigned to $ref.
    • Line 5 dereferences $ref, finding the memory location originally associated with $anon, and assigns that value to $deref.
    • Line 7 correctly prints the memory location originally associated with $anon. The memory has not been deallocated, since $ref still points to it.
    • Line 8 correctly prints the value stored in $deref (42).
    • Line 9 raises a compile-time warning, since the $anon in that print statement is really $main::anon and not the my $anon to which we assigned in line 4 and is now out of scope. A run-time warning is also issued about the attempt to print that undefined variable.

    I encourage you to copy this demo and fool around with it until you feel more comfortable with references. Suggest changing the assignment, eliminating the do-block, taking a reference to $ref, and dropping braces in various places to force scope. (One experiment at a time!) Here's a few other changes to try:

    my $ref     = \do{ @arr = (1, 2, 3) };

    or:

    my @arr = (1, 2, 3); my $ref = \@arr;

    or:
    my $ref      = \(1, 2, 3);

    or:
    my $ref      = [1, 2, 3];

    Can you guess for which of the above print @arr; will not raise a warning?

    Strongly suggest you try perldoc perlref, which goes into much greater detail. Mark Dominus' perldoc perlreftut is an easy introduction.

Re: Dangling Pointer::perl referrence
by shawnhcorey (Friar) on Feb 18, 2010 at 15:22 UTC

    C programmers have a hard time with some of the aspects of Perl because they look similar to constructions in C but act very differently. In C, you are taught that arrays are blocks of memory and their names are just pointers. The following are equivalent in C:

      a[2]
      *(a+2)
      2[a]
    

    In Perl, arrays are more like objects than memory. When you undef an array, you free up its data but it still remains in the symbol table. This means you can reuse it later. In Perl, the following are equivalent:

      undef @arr;
      @arr = ();
    

    The array doesn't go away with undef, just its data. Like in the following:

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    
    use Data::Dumper;
    
    # Make Data::Dumper pretty
    $Data::Dumper::Sortkeys = 1;
    $Data::Dumper::Indent   = 1;
    
    # Set maximum depth for Data::Dumper, zero means unlimited
    $Data::Dumper::Maxdepth = 0;
    
    my @arr = ( 1, 2, 3, );
    print Dumper \@arr;
    
    undef @arr;
    print Dumper \@arr;