Can someone provide an explanation of a weak reference in Delphi?
I noticed that the concept is often mentioned in some library/framework source code I scrutini
Instances that reference each other by interface references keep each other alive in a reference count based interface implementation.
A weak reference is used to break the "keep each other alive" bear hug. This is done by declaring one reference as a pure pointer to circumvent the reference counting mechanism.
IFriend = Interface(IInterface)
end;
TFriend = class(TInterfacedObject, IFriend)
private
FFriend: IFriend;
end;
var
Peter: IFriend;
John: IFriend;
begin
Peter := TFriend.Create;
John := TFriend.Create;
Peter.Friend := John;
John.Friend := Peter;
end;
Even when Peter and John go out of scope, their instances are kept around because their mutual reference keeps their refcount from dropping to zero.
The problem is more commonly found in composite patterns (parent - child relationships) where the child has a back reference to the parent:
ISomething = Interface(IInterface)
end;
TSomething = class(TInterfacedObject, ISomething)
end;
TParent = class(TSomething)
FChildren: TInterfacedList;
end;
TChild = class(TSomething)
FParent: ISomething;
end;
Again, parent and child can keep eachother around because their mutual reference keeps their refcount from dropping to zero.
This is solved with a weak reference
:
TChild = class(TSomething)
FParent: Pointer;
end;
By declaring the FParent as a "pure" pointer the reference counting mechanism doesn't come into play for the back reference to the parent. When a parent goes out of scope, its reference count now can drop to zero because its children no longer keep its ref count above zero.
Note This solution does require careful attention to lifetime management. Children can be kept alive beyond the life time of the parent when something on the "outside" of these classes keeps a reference to a child. And this can lead to all sorts of interesting AV's when the child assumes the parent reference always points to a valid instance. If you need it, make sure that when the parent goes out of scope, it makes the children nil their back references before it nils its own references to its children.