Нет, я не думаю, что такое может случиться. Строковая переменная может получить значение, которого вы не ожидали, но это не приведет к утечке памяти. Рассмотрим это:
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
«s аргумент объявляться константой, поэтому, мол, он не изменится. Но тогда One
обходит это путем изменения фактического параметра вместо формального параметра. Процедура Two
«знает», что аргумент One
является константой, поэтому он ожидает, что фактический параметр сохранит свое первоначальное значение. Утверждение терпит неудачу.
Строка не просочилась, но этот код демонстрирует, как вы можете получить ссылку обвисшей ссылки для строки. 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);
Это похоже на то, что я думал, но это не AV в 2009 году, и я считаю, что вы говорили. –
Это не AV, потому что в Delphi 2009 «const» теряет свою функциональность, если $ STRINGCHECKS включены. –