访问 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
在引用项目后不被修改,这对您来说可能太过拘束。
我有一个程序使用 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
在引用项目后不被修改,这对您来说可能太过拘束。