popoveo писал(а): опять не понятно, где увеличивать и уменьшать количество ссылок
При любой передаче объекта «по значению», а тот, кому передали, уменьшает, когда закончит работать. В частности: функция ожидает аргументы инкрементнутыми и освобождает их; если функция возвращает объект, она инкрементирует его счётчик, а когда вызвавший закончит с ним работать — декрементирует; конструкторы всегда возвращают объект со счётчиком = 1. Ну, так в моём варианте (и так компилятор работает со всеми автотипами, кроме интерфейсов).
Интерфейсы чуть по-другому сделаны (предполагается, что конструктор возвращает объект с нулём ссылок), поэтому у них есть неприятная багофича:
- Код: Выделить всё
 {$mode objfpc} {$h+} {$apptype console} {$modeswitch duplicatelocals}
uses
   heaptrc;
type
   IString = interface
      function GetValue: string;
      property Value: string read GetValue;
   end;
   StringWrapper = class(TInterfacedObject, IString)
      value: string;
      constructor Create(const value: string);
      function GetValue: string;
   end;
   constructor StringWrapper.Create(const value: string);
   begin
      inherited Create;
      self.value := value;
   end;
   function StringWrapper.GetValue: string;
   begin
      result := value;
   end;
   operator +(a, b: IString): IString;
   begin
      result := StringWrapper.Create(a.Value + b.Value);
   end;
   procedure Test;
   begin
      writeln((StringWrapper.Create('1') + StringWrapper.Create('2') + StringWrapper.Create('3')).Value);
   end;
begin
   Test;
   DumpHeap;
   readln;
end.
Если в operator+ передать const-ссылку на объект, созданный на месте (здесь операнды такими и являются), его счётчик никогда не увеличится с нуля, соответственно, не уменьшится и объект утечёт. Это не считая того, что подсчёт ссылок работает только для переменных интерфейсного типа, а не классового, поэтому, единожды отдав класс в интерфейсную переменную, в дальнейшем с ним можно работать только через интерфейсы.