不,我不认为这样的事情会发生。字符串变量可能会获得一个您没有预料到的值,但它不会泄漏内存。考虑一下:
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);