関数でパラメーターを使用する場合、少なくともそれらすべてのパラメーターをローカル変数に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.
揮発性文字列とconst文字列は事実上2つの異なるタイプであるため(従来のコンパイラはそれらを異なる方法で処理します)、データ変換が追加されている必要があります。const-string関数を呼び出して、揮発性文字列パラメータを渡すと、Delphiは使用カウンタを増やして減らすことができます。関数の終了後。const-stringsパラメーターを次のconst-string関数に渡すのは、現在のようになります。コンパイラーが揮発性文字列をconst stringに型キャストすると、そのままにしておくことができます。
悲しいことに、そうではありません。そして、ここにドラゴンがいます。
したがって、関数にconst文字列パラメーターがある場合は、関数から呼び出さないか、それらのパラメーターをローカル変数にキャッシュします。