gpt4 book ai didi

delphi - 为什么 Generics.Collections.TObjectList.List 不安全?

转载 作者:行者123 更新时间:2023-12-03 15:04:05 24 4
gpt4 key购买 nike

Generics.Collections 中的

TListTOjectList 有一个 .List 属性,它是一个枚举器。

例如:

oList := TObjectList<TItem>.Create;
// Add items to oList
for Item in oList.List do begin
// Do something with Item
end;

这很简洁,但会产生严重的后果。 .List 只是读取 FList (TListTObjectList 上的私有(private)声明),它仅仅是一个 arrayofT.

由于每当添加的项目超出其大小时,动态数组的大小就会加倍,这意味着它有空间容纳未使用的项目。

如果您添加了 3 个 TItem,则实际的 FList 的长度为 4 个项目,第四个(也是最后一个)项目为 nil >.

因此,使用 TObjectList.List 是不安全的,因为如果您的 TObjectList 没有2 的幂的 .Count 值(例如 1、2、4、8、16 等)。

以下代码可能会引发访问冲突:

for Item in oList.List do begin
Writeln(Item.ClassName);
end;

当然,安全的解决方案是使用 .Count 进行简单迭代:

for I := 0 to oList.Count - 1 do begin
Item := oList.Items[I];
Writeln(Item.ClassName);
end;

不如枚举器漂亮。 (当然,您还可以检查 Item 是否为 nil。)

我的问题是:

  • 为什么 .List 不是实际的枚举器?
  • TList/TObjectList 一个实际的枚举器吗?

这是来自 TForm 的示例(其中 btn1 只是添加一行,mmo1 是一个 TMemo )。

procedure TForm2.btn1Click(Sender: TObject);
var
Line: string;
begin
Line := 'Line';
mmo1.Lines.Add(Line);
fList.Add(Line);
mmo1.Lines.Add(Format('Count: %d; Actual length: %d', [fList.Count, Length(fList.List)]));
for Line in fList.List do begin
mmo1.Lines.Add(Format('Found: "%s"', [Line]));
end;
end;

现在,使用string 不会引发访问冲突。但是当我点击 3 次时,我得到以下信息:

Count: 3; Actual length: 4
Found: "Line"
Found: "Line"
Found: "Line"
Found: ""

最佳答案

TList<T> and TOjectList<T> in Generics.Collections have a List property, which is an enumerator.

不,事实并非如此。 List属性是一个动态数组。动态数组内置了对枚举的支持。

Since a dynamic array is doubled in size whenever an item is added beyond its size, it means it has space for non-used items.

这也不是真的。动态数组不会自动调整大小。必须通过调用 SetLength 显式调整它们的大小。 。 TList<T>类通过调用 SetLength 来管理存储列表内容的底层动态数组的容量。 .

Why is List not an actual enumerator?

List 如果我记得的话,最近在 XE3 中添加了属性。其目的是允许直接访问底层列表,这是没有其他方法可以实现的。

有时,为了提高效率,如果您想修改列表的内容,您可能更愿意避免复制。例如,假设您的列表包含大小为 1KB 的记录。如果您想修改每个记录中的单个 bool 值,而不使用 List属性,您最终将整个 1KB 记录复制两次。只是修改一个 bool 值。

当然,访问底层存储的成本是您暴露于内部实现细节。 Embarcadero 本来可以实现一些功能,让您以更安全的方式进行访问,但无论出于何种原因,他们选择了这条路线。我想我可能已经创建了一个返回指向项目的指针的索引属性。

所以,这确实是 List 的唯一用例属性(property)。除非您确实需要直接访问底层存储,否则不要使用 List 。当然,如果文档能够解释其中的任何内容就好了,但事实就是如此。

Does TList<T> have an actual enumerator?

是的。

var
Item: SomeType;
MyList: TList<SomeType>;
....
for Item in MyList do
Item.Foo();

关于delphi - 为什么 Generics.Collections.TObjectList.List 不安全?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22713780/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com