当您const string
在函数中使用参数时,您向 Delphi 编译器承诺您不会从中调用任何其他函数,至少在您将所有这些const string
参数复制到您将拥有的局部变量之前不会。
https://github.com/the-Arioch/XE2_AutoOpenUnit/blob/master/Delphi_String_Bug/Girli_str_2xFree_Minimized.dpr
https://plus.google.com/+AriochThe/posts/WB3toSpAdfA
program Girli_str_2xFree_Minimized;
{$APPTYPE CONSOLE}
// initial mini-demo by Ãèðëèîíàéëüäî - http://www.sql.ru/forum/memberinfo.aspx?mid=249076
// variance IfDef's re-added by Arioch (orginal reporter)
uses
SysUtils;
{.$Define TestBug_Impl_Exit}
{.$Define TestBug_Impl_AsIs}
{.$Define NewStr_Unique}
var
rFile: string;
// global or local does not matter.
// originally it was an object member.
{$IfNDef TestBug_Impl_Exit} {$IfNDef TestBug_Impl_AsIs}
function TestBUG(const S: string): string;
begin
Result := S;
end;
{$EndIf}{$EndIf}
{$IfDef TestBug_Impl_AsIs}
procedure TestBUG(const S: string; var Result: string);
begin
Result := S;
end;
{$EndIf}
{$IfDef TestBug_Impl_Exit}
function TestBUG(const S: string): string;
begin
Exit(S);
end;
{$EndIf}
procedure Test(const FileName: string);
{$IfDef TestBug_Impl_AsIs} var unnamed_temp: string; {$EndIf}
begin
// rFile := FileName.SubString(0, Length(FileName)); // unavail in XE2
{$IfNDef NewStr_Unique}
rFile := Copy(FileName, 1, Length(FileName));
// reference-counting broken, de facto writes into const-string (destroys it)
{$Else}
rFile := FileName; // no bug, reference-counting proceeded normally!
UniqueString(rFile);
{$EndIf}
{$IfNDef TestBug_Impl_AsIs}
TestBUG(FileName); // try to use the const-pointer to the old string
{$Else}
TestBUG(FileName, unnamed_temp);
{$EndIf}
end; // <== Fatality here
begin
try
try
rFile := ParamStr(0);
Test(rFile);
Writeln('Safely returned from the hazardous function without memory dislocations.');
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
finally
Writeln;
Writeln('Read the output. Press ENTER to terminate the program.');
Readln;
end;
end.
由于 volatile string 和 const string 实际上是两种不同的类型——经典编译器对它们的处理方式不同——应该添加数据转换:当调用 const-string 函数时传递它 volatile-string 参数 Delphi 可以增加使用计数器并减少它函数退出后。将 const-strings 参数向下传递到下一个 const-string 函数就是现在的样子,一旦编译器将 volatile 字符串类型转换为 const 字符串,它就可以保持不变。
可悲的是,事实并非如此。这里是龙。
因此,如果您的函数具有 const 字符串参数 - 要么不要从中调用,要么将这些参数缓存到本地变量中。