6

最初の手順:

procedure TestOne(List : TStringList);
var
  TempList : TStringList;
begin
  TempList := TStringList.Create;
  TempList.Add('Test');
  List := TempList;
  TempList.Free;
end;

procedure TForm1.Button1Click(Sender : TObject);
var
  aList : TStringList;
begin
  aList := TStringList.Create;
  TestOne(aList);
  Memo1.Lines := aList;
end;

ボタンをクリックしても、メモには何も表示されず、ブレークポイントには、この行を実行しない手順が表示されます:</p>

  List := TempList;

この行

そして、私は手順を変更します:

procedure TestTwo(List : TStringList);
var
  TempList : TStringList;
begin
  TempList := TStringList.Create;
  TempList.Add('Test');
  List.Text := TempList.Text;
  //or
  List.Assign(TempList);
  //List := TempList;
  TempList.Free;
end;

今回は動作します。

では、なぜ使えないのList := TempList;でしょうか。

4

1 に答える 1

15

変数を値で渡すと、Delphi はパラメータ値のコピーをスタックに作成し、メソッド内でそのパラメータに加えられたすべての変更はそのコピーに対して行われます。

これは、Turbo Pascal の時代から、そしておそらく最初から Pascal が機能していた方法です。このことを考慮:

procedure TestInt(Int: Integer);
begin
  Int := 10;
  Writeln(Int); //writes 10
end;

var
  I: Integer;
begin
  I := 5;
  Wirteln(I); //writes 5
  TestInt(I);
  Writeln(I); //also writes 5
end.

ここで、オブジェクトをパラメーターとして渡す場合、オブジェクト変数がオブジェクトへの参照であることを覚えておく必要があります (オブジェクトが実際にヒープに格納されているアドレスへのポインター)。ただし、パラメーターを参照で渡す場合は、上記の規則が引き続き適用されます。参照のコピーがスタックに作成されます。メソッド/プロシージャ内でその参照に加えた変更は、そのコピーに対して行われます。

この行List := TempList;は、参照を変更して、別のメモリ位置にある別のオブジェクトを指すようにするだけです。その値は、プロシージャーが戻るときに失われます。同じように、プロシージャーが戻るときに整数値が失われTestIntます。

行が決して実行されないという事実は、オプティマイザが動作していることです。新しい値は使用されないため、オプティマイザーは最終的な exe ファイルから割り当てを削除し、行は実際には実行されません。

パラメーター宣言を変更して参照 (var パラメーター) で渡すことができますが、メモリ リークを回避するためにオブジェクトのメモリを解放する責任者を考慮する必要があるため、オブジェクトを操作する場合はお勧めできません。

何を達成しようとしているのかはわかりませんが、代入はあるリストから別のリストに文字列をコピーするため、Assign が適しているようです。次のように、リストを直接操作し、TempList を使用しないことを検討する必要があります。

procedure TestOne(List : TStringList);
begin
  List.Clear;
  List.Add('Test');
end;

procedure TForm1.Button1Click(Sender : TObject);
var
  aList : TStringList;
begin
  aList := TStringList.Create;
  TestOne(aList);
  Memo1.Lines := aList;
end;

ご覧のとおり、結果は同じです。

編集

Rob はコメントで重要なことを指摘したので、Button1Click メソッドの最後の行が機能する理由について説明します。Memo1.Lines := aList;

これは直接割り当てのように見えますが、その行でDelphi プロパティを扱っていることを知っておく必要があります。

プロパティは、フィールドと同様に、オブジェクトの属性を定義します。ただし、フィールドは内容を調べて変更できる単なるストレージの場所ですが、プロパティは特定のアクションをそのデータの読み取りまたは変更に関連付けます。プロパティは、オブジェクトの属性へのアクセスを制御し、属性を計算できるようにします。

プロパティの宣言では、名前と型を指定し、少なくとも 1 つのアクセス指定子を含めます。

TCustomMemo の Lines プロパティがどのように宣言されているかを見てみましょう。

  TCustomMemo = class(TCustomEdit)
  ..
  ..
    property Lines: TStrings read FLines write SetLines;

つまり、プロパティに値を代入するときは、実際には SetLines メソッドを呼び出して、次のように Value をパラメーターとして渡します。

  Memo1.SetLines(AList);

SetLines の実装は次のようになります。

procedure TCustomMemo.SetLines(Value: TStrings);
begin
  FLines.Assign(Value);
end;

したがって、最後に同じ TStrings.Assign 呼び出しを発行して、すべての文字列をソース リストから宛先リストにコピーします。

これは、オブジェクト プロパティを処理し、オブジェクトに対する明確な所有権を維持する Delphi の方法です。各コンポーネントは独自のサブオブジェクトを作成して所有し、あなたはオブジェクトを作成して所有します。

プロパティに対する代入演算子 ( := ) はシンタクティック シュガーであり、コンポーネントの作成者が値の読み取りまたは書き込み時に副作用を導入できるようにし、プログラマーがプロパティを標準フィールドであるかのように考えて快適に過ごせるようにします。その副作用の。

于 2013-01-23T03:16:36.943 に答える