Нет, я не думаю, что такое может случиться. Строковая переменная может получить значение, которое вы не ожидали, но это не приведет к утечке памяти. Учтите это:
var
Global: string;
procedure One(const Arg: string);
begin
Global := '';
// Oops. This is an invalid reference now. Arg points to
// what Global used to refer to, which isn't there anymore.
writeln(Arg);
end;
procedure Two;
begin
Global := 'foo';
UniqueString(Global);
One(Global);
Assert(Global = 'foo', 'Uh-oh. The argument isn''t really const?');
end;
Здесь аргумент One
объявлен как const, поэтому, предположительно, он не изменится. Но тогда One
обходит это, изменяя фактический параметр вместо формального параметра. Процедура Two
«знает», что аргумент One
является const, поэтому она ожидает, что фактический параметр сохранит свое первоначальное значение. Утверждение не удалось.
Строка не просочилась, но этот код демонстрирует, как вы можете получить свисающую ссылку для строки. Arg
является локальным псевдонимом Global
. Хотя мы изменили Global
, значение Arg
остается нетронутым, и, поскольку оно было объявлено как const, счетчик ссылок строки не увеличивался при входе в функцию. Переназначение Global
сбросило счетчик ссылок до нуля, и строка была уничтожена. Объявление Arg
как var будет иметь ту же проблему; передача его по значению исправит эту проблему. (Вызов UniqueString
просто для того, чтобы убедиться, что строка подсчитывается ссылками. В противном случае это может быть строковый литерал без подсчета ссылок.) Все типы, управляемые компилятором, подвержены этой проблеме; простые типы неуязвимы.
Единственный способ утечки строки - это трактовать ее как нечто отличное от строки или использовать функции управления памятью, не зависящие от типа. Mghie's answer описывает, как трактовать строку как что-то отличное от строки, используя FillChar
, чтобы заглушить строковую переменную. Функции памяти без учета типа включают GetMem
и FreeMem
. Например:
type
PRec = ^TRec;
TRec = record
field: string;
end;
var
Rec: PRec;
begin
GetMem(Rec, SizeOf(Rec^));
// Oops. Rec^ is uninitialized. This assignment isn't safe.
Rec^.field := IntToStr(4);
// Even if the assignment were OK, FreeMem would leak the string.
FreeMem(Rec);
end;
Есть два способа исправить это. Нужно позвонить Initialize
и Finalize
:
GetMem(Rec, SizeOf(Rec^));
Initialize(Rec^);
Rec^.field := IntToStr(4);
Finalize(Rec^);
FreeMem(Rec);
Другой вариант - использовать функции, учитывающие тип:
New(Rec);
Rec^.field := IntToStr(4);
Dispose(Rec);