At 03:24 PM 3/19/2001 -0500, Kort, Eric wrote:
>Perlguts states in the context of av_fetch that "If lval is set then the
>fetch will be part of a store."  I don't understand what that means.

Basically it means that perl will extend the array out for you if you go 
off past the end of the array with the fetch, and that it will return a 
real SV if you fetch from an array entry that was autovivified by an extend.

The details are in av.c, though the source can be a little daunting.

>---8<-----------
>svNewVal = *av_fetch(avImage, i, 0);
>svREFCNT_inc(svNewVal);
>if (av_store(avGrid, i, svNewVal) == NULL )
>{
>   svREFCNT_inc(svNewVal);
>}
>---8<-----------
>
>Any problem there?

Yes. av_fetch doesn't return a copy of a scalar, and av_store doesn't make 
a copy of the scalar being stored. That means that for your code here, both 
arrays hold handles on the same SV, so altering it in one array will alter 
it in both. (You basically are aliasing the SV the same way that foreach or 
@_ does)

>Perlguts also states that I must increment the reference count myself when
>using av_store, and decrement it if the store fails.  May I presume then,
>from the silence on this issue elsewhere in perlguts, that I do not need to
>manage the reference counts myself when using av_fetch and av_push?

Yes and no, respectively. av_fetch returns a pointer to the SV in the 
array, and perl generally assumes you'll make a copy of it if you want to 
put it elsewhere. You may need to increment the refcount for av_push, but 
probably not since you're generally pushing SVs just created with newSV, 
which sets the refcount to 1 to begin with. (Which is where you want it if 
you're pushing it onto an array)

>   In
>other words, is the fetching and storing in the following example, without
>any reference count increments or decrements, ok (this does not leak memory
>as far as I can tell, but I wonder if any experts have any critique of
>this):
>
>---8<-----------
>SV* myFunction(SV* svImage, int iChannel, int iThreshold)
>{
>   AV *avImage, *avMask;
>   int i, iImageA;
>   SV *r;
>   for (i=0; i<(iImageA+1)/3; i++)
>     {
>       if (SvIV(*av_fetch(avImage, i*3+iChan, 0)) > iThresh)
>         {
>           r = *av_fetch(avImage, i*3, 0);
>         } else
>         {
>           r = newSViv(0);
>         }
>         av_push(avMask, r);
>     }
>  return newRV_noinc((SV*)(avMask));
>}
>---8<-----------

You're aliasing the SVs you fetch from the source array and you're not 
getting the refcounts right. Probably the only reason things aren't going 
bang is because you have arrays that don't end up getting GCd.

>As Dan Sugalski described this situation earlier:
>
>*) There's a pointer to an SV in an array
>*) You fetch the pointer out of the array. Now both you and the array have
>a pointer to the same SV
>*) You push the pointer onto the new array. Now you and both arrays have
>pointers to the same SV.
>
>But it appears that the push and fetch macros are taking care of the
>reference counts themselves, since this does not leak memory.  Is that
>right?

Nope.

Check out av.c. You'll see it does very little in the way of refcount 
changes, assuming you'll Do The Right Thing. And since it's easy to do even 
by accident, things generally work out.

                                        Dan

--------------------------------------"it's like this"-------------------
Dan Sugalski                          even samurai
[EMAIL PROTECTED]                         have teddy bears and even
                                      teddy bears get drunk

Reply via email to