0

TListViewいくつかのデータを視覚化して保存するために使用するプログラムがあります。TListitemの data プロパティには、レコードへのポインタが次のように入力されます。

type
  TWatch = record
    name : string;
    path : string;
    //...
end;

procedure TfrmProcessWatcherMain.AddWatchToListView(AWatch: TWatch);
var
  ANewWatch : TListItem;
begin
  ANewWatch := lvWatches.Items.Add; //lvWatches is TListview
  //...
  ANewWatch.Data:= @AWatch;
end;

どういうわけかこのデータを取得しようとすると、アクセス違反エラーが発生します。すべてが合法であるように見えるので、これは私にとってまったく驚きです。取得のコードは次のとおりです。

if(lvWatches.Selected <> nil) then begin
  tempWatch := TWatch(lvWatches.Selected.Data^); // AV here
  ShowMessage(tempWatch.name);

またAWatch、最初の関数に渡されるものは、

WatchList : TList<TWatch>;

そのため、他の方法を使用してアクセスできます

4

1 に答える 1

3

問題は@AWatch、ローカル変数のアドレスです。AddWatchToListView返品が範囲外になりAWatch、その住所が無効になった場合。

ローカル変数のアドレスを取得する代わりに、を使用してヒープにレコードを割り当てる必要がありますNew

procedure TfrmProcessWatcherMain.AddWatchToListView(AWatch: TWatch);
var
  ANewWatch : TListItem;
  P : ^TWatch;
begin
  ANewWatch := lvWatches.Items.Add;
  New(P);
  P^ := AWatch;
  ANewWatch.Data:= P;
end;

Disposeリスト項目が破棄されるたびに、メモリの割り当てを解除する必要があります。リストビューのOnDeletionイベントを使用してそれを行います。

または、アイテムのインデックスを に保存することもできますWatchList。または、次のように取得される のレコードのアドレスWatchList: @WatchList.List[Index]。これらのオプションはどちらも、WatchListアイテムへの参照が取得された後に変更されないことに依存しているため、制約が強すぎる場合があります。

于 2015-03-29T08:25:50.493 に答える