1

私は、コールバックプロシージャを持っている:ローカル配列を永続的にする方法は?

type 
    TInitCallback = procedure (var Data: Pointer); 

アイデアは、初期化Data後に何を指しているかもしれないということです。

私はそれが新たに作成された配列を指す必要があることのようにコールバックし、init Dataに、この手順を割り当てるしようとしました:

type 
    TBoolArray = array of Boolean; 

procedure InitData(var Data: Pointer); 
var 
    BoolArray: TBoolArray; 
    i: Integer; 
begin 
    SetLength(BoolArray, 10); 
    for i := 0 to Length(BoolArray) - 1 do 
    BoolArray[i] := False; 
    Data := BoolArray; 
end; 

は、しかし、私は参照カウンタがために増加していることを確認していません配列の場合はData := BoolArray;を割り当てます。言い換えれば - 私は配列がプロシージャを離れた後にまだメモリに残っているのか、解放されたのかわからないのですか?

後でプログラムを実行すると、他の構造(この配列と何の関係もないレコード)でデータを変更すると、この変更によって、以前に割り当てられた配列(Data)が変更されます。

この説明の1つは、コールバックを離れるときに配列用のメモリが解放され、レコード用にもう一度再利用されたことです。

したがって、InitDataコールバックを残した後でも配列は割り当てられたままですか?もしそうでなければ、それを割り当てたままにする方法。コールバックのシグネチャを変更したくない、新しいパラメータを導入したり、関数に変更することはできません。

ありがとうございます。

答えて

5

Dataに割り当てると、ダイナミックアレイの参照カウントがインクリメントされないことが前提です。これは、InitDataが返されたときに、ローカル配列が範囲外になることを意味します。したがって、あなたのコードは壊れています。

最も簡単な解決策は、TInitCallbackの定義を動的配列を使用するように変更してから、参照メカニズムがあなたのライフタイムを管理することです。インターフェースを変更したくないので、少なくとも次のオプションがあります。

  1. BoolArrayをグローバル変数にします。これは、アプリケーションにインスタンスが1つしかない場合にのみ機能します。
  2. BoolArrayのタイプを^TBoolArrayに変更し、Newを使用してこれをヒープに割り当てます。 Disposeを呼び出して配列の割り当てを解除する別のプロシージャを追加する必要もあります。
  3. オプション2と非常によく似て、クラス内に配列をラップします。クラスインスタンスはポインタに安全に格納できます。再び、Freeを呼び出すことによってクラスインスタンスを破棄する別の関数が必要になります。
関連する問題