Путем я делаю это, у меня есть пустой репозиторий Мерзавца на моем сервере развертывания, где я продвигаю изменения. Тогда я вхожу в систему сервера развертывания, изменяюсь на фактический каталог документов веб-сервера и делаю получение по запросу мерзавца. Я не использую рычагов, чтобы попытаться сделать это автоматически, которое походит на большую проблему, чем это стоит.
На самом деле, передача строки как CONST или не const одинакова с точки зрения счетчика ссылок в Delphi 2007 и 2009. Был случай, когда строка была передана как CONST, вызывала нарушение доступа. Вот проблема первая
type
TFoo = class
S: string;
procedure Foo(const S1: string);
end;
procedure TFoo.Foo(const S1: string);
begin
S:= S1; //access violation
end;
var
F: TFoo;
begin
F:= TFoo.create;
try
F.S := 'S';
F.Foo(F.S);
finally
F.Free;
end;
end.
Нет, я не думаю, что такое может случиться. Строковая переменная может получить значение, которого вы не ожидали, но это не приведет к утечке памяти. Рассмотрим это:
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, поэтому предположительно он не изменится. Но затем Один
обходит это, изменяя фактический параметр вместо формального. Процедура Two
"знает", что аргумент One
является const, поэтому он ожидает, что фактический параметр сохранит свое исходное значение. Утверждение не выполняется.
Строка не просочилась, но этот код демонстрирует, как можно получить висящую ссылку для строки. Arg
- это локальный псевдоним Global
. Хотя мы изменили Global
, значение Arg
осталось нетронутым, и поскольку оно было объявлено как const, счетчик ссылок строки не увеличивался при входе в функцию. При переназначении Global
счетчик ссылок сбрасывается до нуля, и строка уничтожается. Объявление Arg
как var вызовет ту же проблему; передача по значению решит эту проблему. (Вызов UniqueString
предназначен только для того, чтобы убедиться, что строка подсчитывается по ссылкам. В противном случае, это может быть строковый литерал без подсчета ссылок.) Все типы, управляемые компилятором, подвержены этой проблеме; простые типы невосприимчивы.
Единственный способ утечки строки - это рассматривать ее как нечто иное, чем строка, или использовать функции управления памятью, не поддерживающие типы. Ответ Мги описывает, как обрабатывать строку как нечто отличное от строки, используя 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);
Я не знаю о проблеме во втором абзаце, но меня однажды укусила утечка строк в записи.
Если вы вызываете FillChar () для записи, содержащей строки, вы перезаписываете счетчик ссылок и адрес динамически выделяемой памяти с нулями. Если строка не пуста, это приведет к утечке памяти. Чтобы решить эту проблему, необходимо вызвать Finalize () для записи перед очисткой памяти, которую она занимает.
К сожалению, вызов Finalize () , когда нет элементов записи, требующих завершения причин подсказка компилятора. Со мной случилось так, что я закомментировал вызов Finalize () , чтобы заглушить подсказку, но позже, когда я добавил к записи строковый член, я пропустил раскомментирование вызова, поэтому произошла утечка. К счастью, я обычно использую диспетчер памяти FastMM в наиболее подробных и параноидальных настройках в режиме отладки, поэтому утечка не осталась незамеченной.
Подсказка компилятора, вероятно, не такая уж хорошая вещь, молча опуская ИМХО, вызов Finalize () , если он не нужен, будет намного лучше.
Я думаю это могло быть похоже на то, о чем я думал. Это обратная утечка строки, строка, которая собирается рано:
var
p : ^String;
procedure InitString;
var
s, x : String;
begin
s := 'A cool string!';
x := s + '. Append something to make a copy in' +
'memory and generate a new string.';
p := @x;
end;
begin
{ Call a function that will generate a string }
InitString();
{ Write the value of the string (pointed to by p) }
WriteLn(p^); // Runtime error 105!
{ Wait for a key press }
ReadLn;
end.