8

多くのメモリ割り当てと同じ数の FreeMem 呼び出しがあります。私が持っていなかったのは、freemem を呼び出してポインターが nil かどうかを確認する前のチェックと、ポインターを nil に設定するために解放した後の行です。

これを行う関数を作成しようとしました

procedure FreeMemAndNil(p: Pointer; size: Integer = -1);
begin
  if p <> nil then
  begin
    if size > -1 then
      FreeMem(p, size)
    else
      FreeMem(p);
    p := nil;
  end;
end;

しかし、問題があります。パラメーターが可変 (var p: ポインター) ではないため、元のポインターを nil に設定することはできません。ただし、var を使用することはできません。これを行うと、型がまったく同じ型 (ポインター) である必要があるとコンパイラが文句を言うからです。渡すポインターは、任意の型 (PChar、通常のポインターなど) へのポインターである可能性があります。

これを修正するにはどうすればよいですか? より良い解決策はありますか?

4

4 に答える 4

14

その関数に任意のポインター値を渡すことができるようにするには、FreeAndNil と同じモデルに従い、型指定されていないパラメーターを渡す必要があります。それ以外の場合、コンパイラは、実際のパラメーターの型と仮のパラメーターの型が同一ではないというエラーを正しく表示します。FreeMem を呼び出すときに、型指定されていないパラメーターを Pointer に型キャストします。

あなたはその関数でいくつかの無意味なことをしています。

まず第一に、nil ポインターの解放は常に安全であるため、FreeMem を呼び出す前にそれを確認する必要はありません。心配する必要がある非 nil ポインターを解放していますが、それからあなたを保護できる関数はありません。

次に、FreeMem の size パラメータは長年無視されてきました。以前は、そのパラメーターを指定した場合、GetMem に渡されるサイズと一致する必要がありましたが、現在、FreeMem はそのパラメーターを完全に無視します — コンパイラーはそのパラメーターを関数に渡すことさえしません。

上記のすべてを念頭に置いて、関数は次のようになります。

procedure FreeMemAndNil(var P);
var
  Tmp: Pointer;
begin
  Tmp := Pointer(P);
  Pointer(P) := nil;
  FreeMem(Tmp);
end;

GetMem で割り当てられたポインターではないものに対して、誤ってその関数を呼び出さないように注意してください。型付きパラメーターを使用している場合のように、コンパイラーはそれをキャッチしません。GetMem で割り当てられていないものを解放しようとすると、おそらく EInvalidPointer 例外が発生しますが、渡した変数は後で nil のままです。これは、FreeAndNil が機能するのと同じ方法です。

于 2010-08-11T18:09:51.463 に答える
9

オブジェクトに対してこれを行う FreeAndNil と呼ばれる SysUtils のプロシージャがあります。これは、 TObject にキャストする型指定されていないvarパラメータを使用して行われます。TObject 以外のものを渡さないようにするのは、ユーザーの責任です。必要に応じて、ここで同様のことを行うことができます。ただ気をつけてください。それを行うと、型の安全性はありません。

于 2010-08-11T17:30:56.550 に答える
6

Mason Wheelerが言ったように、SysUtilsユニットのFreeAndNilがオブジェクト参照に対して行うのと同じトリックを使用する必要があります。 だから私はあなたのコードを修正し、それをユニットテストしました、そしてこれはうまくいきます:

procedure FreeMemAndNil(var ptr; size: Integer = -1);
var
  p: Pointer;
begin
  p := Pointer(ptr);
  if p <> nil then
  begin
    if size > -1 then
      FreeMem(p, size)
    else
      FreeMem(p);
    Pointer(ptr) := nil;
  end;
end;

--jeroen

PS:Rob Kennedyは、インターネット上の彼の型なしパラメーターページへのリンクがある、型なし変数パラメーターに関する良い答えを書きました。

PS2:参考:SysUtils.pasのKylixバージョンはオンラインであり、FreeAndNilはDelphiの場合と同じです。

于 2010-08-11T17:58:42.190 に答える
4

私はポインタ/メモリ操作のために ReallocMem を頻繁に使用する傾向があります。

通話中

ReallocMem(P,0)

ポインターを Nil に設定します。

使用について知っておく必要があることの 1 つは、P を ReallocMem に渡す前に初期化する必要があることです。

于 2010-08-12T17:13:51.577 に答える