4

この短いDelphi手順を検討してください。

procedure TfrmXQuery.FieldListFillFromDefault;
var
  field_list: TStringList;
begin
  try
    if x <> '' then begin
      field_list := TStringList.Create;
      {do some stuff with field_list}
    end;
  finally
    if field_list <> NIL then 
    begin
      field_list.Free;
    end;
  end;
end;

これをDelphi3で実行すると、x =''であるため、field_listは作成されません。

  1. なぜfield_list <> NILですか?
  2. オブジェクトは次のように初期化されていませんNILか?
  3. そうでない場合NILはそれは何ですか?
  4. 割り当てられていない場合、どうすれば割り当てられてNILいるかどうかを知ることができFreeますか?関数はAssigned教えてくれません:if Assigned(an_object)と同等ですif an_object = NIL
4

2 に答える 2

8

問題は、if x = ''とにかくfinally起こるということです。field_listは初期化されていない場合にのみ初期化されるためx <> ''、初期化されていないローカル変数であるため、その時点より前のランダムなメモリ位置になります。ランダムな値は、field_list.freeと等しくないため、を呼び出すことができますnil。(Delphiはローカル変数(関数またはプロシージャ内で宣言された変数)を初期化しません。)

var
  somevar: sometype;    
begin
  // at this point, somevar is just a chunk of memory that
  // holds whatever happens to be in that chunk
  somevar := nil;         // now somevar = a specific value you can test

  // other code
end;

<> nilコードを正しく構造化すれば、(他の人がコメントで指摘しているように)テストする必要はありません。

procedure TfrmXQuery.FieldListFillFromDefault;
var
  field_list  : TStringList;
begin
  if x <> '' then 
  begin
    field_list := TStringList.Create;
    try
      {do some stuff with field_list}
    finally
      field_list.Free;
    end;
  end;
end;

(ヒントと警告をオンにすると、コンパイラーはfield_list may not have been initializedそれを通知します。これは、これを自分で解決するのに役立ちます。)

于 2013-03-16T03:31:34.003 に答える
-3

質問への回答:

  1. なぜfield_list <> NILですか? Delphiはローカルオブジェクトを初期化しません。詳細については、「オブジェクトがデフォルトでnilにならないのはなぜですか? 」を参照してください。およびdelphi変数はデフォルトで値で初期化されていますか?

  2. オブジェクトは次のように初期化されていませんNILか?グローバルオブジェクト:はい。ローカルオブジェクト:いいえ。

  3. そうでない場合NILはそれは何ですか?ポインタが無効です。

  4. 割り当てられていない場合、どうすれば割り当てられてNILいるかどうかを知ることができFreeますか?コードを再編成する必要があります(以下を参照)。 関数はAssigned教えてくれません:if Assigned(an_object)はと同等if an_object = NILです。nil(割り当てられていない)ポインターまたは手続き型変数の割り当てられたテスト。<-Delphi3のドキュメントから。初期化されていないローカルオブジェクトにはNILが割り当てられていないためAssigned(an_object)、an_objectがローカルで使用されたことがない場合(NILの割り当てはオブジェクトを使用している)はTRUEを返します。

プロシージャにローカルなオブジェクトはNILに初期化されないため、NILにローカルなすべてのローカルオブジェクトを割り当てる質問のコードを修正しました。ローカルオブジェクトが作成されない場合にFreeがエラーにならないように、ルーチンの最初にこれらの割り当てを行います。また、元の質問から除外されたエラー追跡コードも示しました。

procedure TfrmXQuery.FieldListFillFromDefault;
var
  field_list: TStringList;
  some_other_object: TAnotherObject;
begin
  try
    try
      field_list := NIL;
      some_other_object := NIL;
      if x <> '' then begin
        field_list := TStringList.Create;
        {do some stuff with field_list}
      end;
      {...}
      some_other_object := TSomeOtherObject.Create;
      {...}
    except
      On E : Exception do begin
        ErrorTrackingRoutine(unit_name, name, 'FieldListFillFromDefault', E.message);
      end;
    end;
  finaly
    field_list.Free;
    some_other_object.Free;
  end;
end;

ルーチン全体はによって保護されていtry...exceptます。field_listまたはsome_other_objectが作成された場合、それは解放されます。それらは最初にNILが割り当てられるため、「try ... finally」ブロックで解放しても、作成前に実行時エラーが発生した場合でもエラーは発生しません。

于 2013-03-16T21:51:38.443 に答える