访问 TListItem.Data 导致使用记录时出错

Accessing TListItem.Data leads to an error when using records

我有一个程序使用 TListView 来可视化和存储一些数据。 TListitem 的数据 属性 填充了指向记录的指针,如下所示:

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>;

因此可以使用其他方法访问

问题是@AWatch是局部变量的地址。一旦 AddWatchToListView returns 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 在引用项目后不被修改,这对您来说可能太过拘束。