Ответ 1
Это происходит, если ваш метод объявлен для передачи интерфейсной переменной как const, например:
procedure Frob(const Grob: IGrobber);
Это не совсем правильно. Чтобы произошла утечка, вам нужно, чтобы в коде не было ничего, что когда-либо ссылалось на вновь созданный объект. Поэтому, если вы пишете:
Frob(grob);
Там нет проблем, потому что интерфейс grob
уже имеет хотя бы одну ссылку.
Проблема возникает при написании:
Frob(TGrobberImplementer.Create);
В этом сценарии ничего не делается для ссылки на интерфейс, и поэтому он просочился. Ну, он будет просочиться, если ничего в реализации Frob
не ссылается на него.
Неужели я сделал что-то плохое?
Ну, это зависит. Я не думаю, что что-то особенно плохое из того, что вы сделали. Существует недостаток в плане производительности, потому что теперь все ваши функции, которые принимают параметры интерфейса, должны будут добавлять и освобождать ссылки, используя неявные блоки try/finally. Только вы можете судить об этом.
Более значимая проблема связана с кодом, который находится вне вашего контроля. Вы даете
procedure OnDocumentComplete(Sender: TObject; const pDisp: IDispatch; var URL: OleVariant);
в качестве примера. Там нет проблемы, потому что вы никогда не называете этот метод. Это обработчик событий, который вы реализуете. Структура вызывает его, и он передает интерфейс, на который уже ссылаются.
Реальная проблема возникает из методов, объявленных в RTL или любого другого кода третьей стороны, который вы вызываете. Если вы вызываете методы, и если они используют аргументы интерфейса const
, вы можете попасть в ловушку.
Это достаточно легко обойти, хотя и утомительно.
grob := TGrobberImplementer.Create;
Frob(grob);
Мое рассуждение о решении проблемы выглядит следующим образом:
- Существует стоимость производительности при передаче параметров интерфейса по значению.
- Я не могу гарантировать, что каждый метод, который я вызываю, будет принимать параметры интерфейса по значению.
- Поэтому я принимаю тот факт, что мне нужно иметь дело с вызовом параметров интерфейса
const
, по крайней мере, некоторое время. - Поскольку мне приходится иметь дело с ним некоторое время, и, поскольку я ненавижу несогласованность, я предпочитаю заниматься этим все время.
- Поэтому я решил сделать все параметры интерфейса в методах, которые я пишу,
const
. - И поэтому я уверен, что никогда не передаю интерфейс в качестве аргумента, если он уже не ссылается на переменную.