My main concern was with the case where the same ref object is shared among 
several parent objects. Setting the field to nil in the destructor would have 
the side effect of decrementing shared object's reference count, and hence 
delay destroying the ref object until the last parent object is destroyed.

I had thought that, if `=destroy` for the shared object was explicitly called 
in the parent object's destructor, then the shared object's destructor would be 
called multiple times - once for each parent object's destruction. This would 
obviously be a problem.

But that turns out not to be the case, as the code example below shows. It 
appears that calling `=destroy` on an object does not actually destroy it if 
the reference count is greater than 1.

BTW, I also found out that explicitly decrementing the shared object's 
reference count in the parent's destructor by calling `GC_unref` also works. 
The two different calls seem to have the same effect.
    
    
    type AObj = object
        name: string
    
    proc `=destroy`(x: AObj) =
        echo "Destroying A named ", x.name
    
    proc newAObj(name: string): ref AObj =
        result = AObj.new()
        result.name = name
    
    type BObj = object
        aref: ref AObj
        name: string
    
    proc `=destroy`(x: BObj) =
        echo "Destroying B named ", x.name
        # Commenting out **both** statements below causes a leak - the 
destructor
        #    for aref is never called
        `=destroy`(x.aref)        # Explicit destructor call - this works fine
        # GC_unref(x.aref)        # Explicit reference count decrement - this 
also works fine
    
    proc newBObj(name: string, aref: ref AObj): ref BObj =
        result = BObj.new()
        result.aref = aref
        result.name = name
    
    echo "Creating A"
    var a = newAObj("A#1")
    
    echo "Creating B#1"
    var bobj1 = newBObj("B#1", a)
    
    echo "Creating B#2"
    var bobj2 = newBObj("B#2", a)
    
    echo "Setting A outside of parents to NIL"
    a = nil
    
    echo "Setting B#1 to NIL"
    bobj1 = nil
    
    echo "Setting B#2 to NIL"
    bobj2 = nil
    
    echo "... Done"
    
    
    Run

Reply via email to