Michael G Schwern wrote: > On Sun, Dec 17, 2000 at 12:11:01PM +1100, Jeremy Howard wrote: > > Something to be careful of--it's easy to create a circular reference when > > using method pointers. As a result, neither the referrer nor referee objects > > are ever destroyed. > > > > When using method references it's important that your class keeps track of > > its references, and explicitly removes them when done to allow object > > destruction to occur. Perhaps this could be incorporated into > > Class::MethRef? > > Circular references make my brane hurt, but I don't think there's any > circularlity here. Once the method reference falls out of scope, so > will its reference to the object. Then the object will be garbage > collected when it to falls out of scope. The other way around, if the > object falls out of scope first, the method reference will still work > and the object will finally be destroyed when the meth ref goes away. > The only snag is if you put the method reference on the object its > refering to, that'll be circular. I'll remember to document that caveat. > There's not necessarily any circular reference. The problem is that method references are frequently used to implement event callbacks. This would generally look something like this: ---- do { my $a = new A; my $b = new B; $b->{on_click} = sub{$a->clicked($b);}; $b->do_click; }; print "Out of scope\n"; package A; sub clicked {my $self=shift; my $clicked_by = shift; print "I am clicked\n"; } sub new { my $Proto = shift; my $Class = ref($Proto) || $Proto; my $Self = {}; bless ($Self, $Class); return $Self; } sub DESTROY {print "bye A\n";} package B; sub do_click { my $self=shift; print "Clicking\n"; $self->{on_click}->(); } sub new { my $Proto = shift; my $Class = ref($Proto) || $Proto; my $Self = {}; bless ($Self, $Class); return $Self; } sub DESTROY {print "bye B\n";} ---- The problem is that in this case the destructors are not called immediately after the objects go out of scope--this code prints: ---- Clicking I am clicked Out of scope bye A bye B ---- ...which creates a memory leak in an event loop. The circular reference is generally necessary, because the callback needs to know in what form the click occurred (on object of class A in this case) and what widget was clicked (an object of class B in this case). However, the circular reference is not obvious at first glance--I've seen this kind of memory leak frequently in mod_perl programs, for instance. My objects that get method references always get an explicit destructor, which removes all method references (which are tracked as they are created). Something like this would be nice in a class that creates method references--it would simply need to keep a list of referred objects, and have an explicit destructor that iterates through the references and undefs them. Of course, calling the destructor would be optional where no circular reference exists. Sorry this explanation isn't as clear as it should be--to many pints of Guinness tonight ;-)Thread Previous | Thread Next