Я такой компромисс придумал: наследуем все объекты от TInterfacedObject и храним сильные ссылки как пару
- Код: Выделить всё
var
obj: TMyObject;
objLife: IInterface;
begin
obj := TMyObject.Create; objLife := obj;
...
end;
Нужно придерживаться правила: после создания объекта
сразу же присвоить его парной -Life, и всем остальным, кто хочет продлить жизнь этого объекта, тоже удерживать свою -Life. Преимущество — можно продолжать работать с простой ссылкой на объект, obj, не вводя парных интерфейсов, не работая через поле типа-обёртки и проч.
Для себя в этом варианте я заменил TInterfacedObject на собственную реализацию без интерфейсов (Refcounted) и IInterface на свой managed-тип (Reference). Также конструктор Refcounted принимает life: Reference как
var-параметр (логически
out, но
out генерирует лишний код реинициализации), создаёт объект сразу со счётчиком 1 и присваивает life, что, во-первых, экономит 1 InterlockedIncrement, во-вторых, исключает возможность забыть присвоить Life после создания (но остальные присвоения всё равно остаются на совести пользователя):
- Код: Выделить всё
constructor Refcounted.Create(var life: Reference);
begin
inherited Create;
refcount := 1; life.RawSet(self);
end;
Тогда конструкторы наследников, да и любые функции, создающие и возвращающие пользователю объект, тоже должны это делать и передавать в inherited / конструктор:
- Код: Выделить всё
type
Child = class(Refcounted)
...
end;
constructor Child.Create(...; var life: Reference);
begin
inherited Create(life);
...
end;