I've been poking around for the last couple of days trying to figure out some of the subtleties of global destruction. Digging around Devel::Peek-land is lots of fun, and more than a little educational. Today I found a bug in my code that results in an object's reference count being off by one. I traced the problem back to my overload'ed pre-/post-increment and copy constructor operators.

The problem is that perl increments the reference count when it invokes the copy constructor, but I'm actually trying to return the same reference: I don't want to copy, mutate or re-bless this particular class of objects. I've written some toy code to illustrate my approach and show the problem, and am hoping that someone can suggest another way to tackle this...

My class in question presents a pretty straightforward iterator interface. Each object encapsulates access to a list of records: I overload '++' to move to the next record, and 'bool' to test whether the traversal is complete. As the overload perldocs note, though, using '++' in this way implies a need to overload '=' (the copy constructor), too. Here's a stripped-down illustration:

package Toy_Iterator; use overload '""' => sub { $_[0] }, bool => sub { ! $_[0]->done_p() }, '++' => \&inc, '=' => sub { $_[0] }, ; sub new { my ( $class, $arg ) = @_; my $self = {}; bless $self, $class; $self->set ( $arg ); return $self; } sub set { $_[0]->{_i} = $_[1] } sub get { return $_[0]->{_i} } sub inc { ++$_[0]->{_i} } sub done_p { $_[0]->{_i} > 5 } sub DESTROY { print "Destroying $_[0]\n" } package main; use Devel::Peek; my $a = Toy_Iterator->new ( 2 ); while ( $a++ ) { print "$a -> " . $a->get() . "\n"; } # print "\n"; Dump $a; print "\n"; print "undef'ing \$a...\n"; undef $a; print "done undef'ing\n";

Running this script produces the following output:

Toy_Iterator=HASH(0x80fbc2c) -> 3 Toy_Iterator=HASH(0x80fbc2c) -> 4 Toy_Iterator=HASH(0x80fbc2c) -> 5 undef'ing $a... done undef'ing Destroying Toy_Iterator=HASH(0x80fbc2c)

The problem is indicated by the fact that $a's destructor is not getting called when it should, at the moment of undef'ing, but only later (during global destruction). Uncommenting out the Dump line will show that the REFCNT for the Toy_Iterator object that $a points to is 2, rather than 1 as it should be.

Changing the post-increment in the while statement to a pre-increment eliminates the problem, because the pre-increment overload here doesn't need to call the copy constructor:

Toy_Iterator=HASH(0x80fbc2c) -> 3 Toy_Iterator=HASH(0x80fbc2c) -> 4 Toy_Iterator=HASH(0x80fbc2c) -> 5 undef'ing $a... Destroying Toy_Iterator=HASH(0x80fbc2c) done undef'ing

I've been round and round the overload docs, and tried a bunch of different versions of my '++' and '=' subs. I don't want to clone these objects -- they're pretty heavy-weight and often contain open database handles. Anyway, cloning doesn't seem like the elegant thing to do for this usage case. I thought about writing the copy constructor as a bit of Inline::C that creates the reference using newRV_noinc (or something similar). But that seems like a big kludge.

Any suggestions?


In reply to Post-increments, overloaded mutators, and reference counts by khkramer

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.