19

constプロシージャでパラメータを使用すると、どのような違いがありますか?

たとえば、次の手順を実行します。

procedure DoSomething(Sender: TObject; const Text: String; var Reply: String);
begin
  //Text is read-only and Reply will be passed back wherever DoSomething() was called
  Reply:= Text;
end;

(私が知る限り)値のコピーが作成されて使用されるように、パラメーターのText: String前に接頭辞が付けられます-そして読み取り専用です。const私が疑問に思っていたのは、これがアプリケーションにどのように影響するのかというconstことです。おそらくパフォーマンスのトリック?

4

4 に答える 4

28

ドキュメントの状態を見ると:

「constを使用すると、コンパイラーは構造化パラメーターおよび文字列タイプのパラメーターのコードを最適化できます。また、別のルーチンを参照してパラメーターを意図せずに渡すことに対する保護手段も提供します。」

たとえば文字列の場合、最適化とは、constとして渡すときに追加のrefcountingがないことを意味します。また、constとして渡すことは、それがコピーであることを意味しません。多くの場合、コンパイラは書き込みアクセスを保証しないため、内部的に参照として渡されます。

内部で何が起こっているのかを完全に理解するためのいくつかの非常に興味深い記事:

http://delphitools.info/2010/07/28/all-hail-the-const-parameters

http://vcldeveloper.com/articles/different-function-parameter-modifiers-in-delphi

編集:

constが内部的に参照渡しになる可能性があることを示す簡単な例:

program Project1;

{$APPTYPE CONSOLE}

type
  PMyRecord = ^TMyRecord;
  TMyRecord = record
    Value1: Cardinal;
    Value2: Cardinal;
  end;

procedure PassAsConst(const r: TMyRecord);
begin
  PMyRecord(@r).Value1 := 3333;
  PMyRecord(@r).Value2 := 4444;
end;

procedure PassByVal(r: TMyRecord);
begin
  PMyRecord(@r).Value1 := 3333;
  PMyRecord(@r).Value2 := 4444;
end;

var
  r: TMyRecord;
begin
  r.Value1 := 1111;
  r.Value2 := 2222;
  PassByVal(r);
  Writeln(r.Value1);
  Writeln(r.Value2);

  PassAsConst(r);
  Writeln(r.Value1);
  Writeln(r.Value2);

  Readln;
end.
于 2012-06-12T17:30:24.663 に答える
9

constプレフィックスがない場合、コンパイラーは、パラメーターを変更することを想定する必要があります。これは、それをコピーして非表示の試行を設定することを意味します...最後にローカル文字列変数を破棄するため、constによってパフォーマンスが大幅に向上する場合があります。また、生成されたコードが小さくなります。

于 2012-06-12T17:26:16.933 に答える
1

constを使用する場合の効率に関する以前の回答に加えて(つまり、コンパイラーが変数をコピーする必要がない)、Interfaceパラメーターを指定してconstを使用すると、参照カウントのトリガーが防止されます。

于 2012-06-12T18:02:16.550 に答える
0

関数でパラメーターを使用する場合、少なくともそれらすべてのパラメーターをローカル変数に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文字列パラメーターがある場合は、関数から呼び出さないか、それらのパラメーターをローカル変数にキャッシュします。

于 2018-08-16T19:29:48.370 に答える