理解TList<RecordType>的内存分配

3

我需要存储一个 TList,其中包含一些可以在 Delphi 中轻松实现为记录的内容(五个简单字段)。但是,当我执行 TList<TMyRecordType>.Add(R) 时,不清楚会发生什么。

由于 R 是在创建 my TList 的过程中的一个局部变量,所以我认为它的内存将在函数返回时释放。这会在列表中留下一个无效的记录指针吗?还是列表知道要进行复制并分配?如果是前者,我假设我需要使用 New() 和 Dispose() 手动管理 R 的内存,对吗?

另外,我可以通过简单地声明字段为公共字段(甚至不必费心制作正式属性)来将我的记录类型“提升”为类类型。那样可以吗?还是我应该花时间构建具有私有字段和公共属性的类?

1个回答

11
简化版:记录是数据块,通过传递值的方式进行传递——默认情况下是复制它们——TList<T>将值存储在类型为T的数组中。因此,TList<TMyRecordType>.Add(R)将复制值R到位置Count处的数组中,并将Count增加一。无需担心内存的分配或释放。
更复杂的问题通常不需要担心:如果您的记录包含字符串类型、接口类型、动态数组或本身包含这些类型之一的字段,则不仅仅是简单的数据复制;而是使用System.pas中的CopyRecord,确保引用计数正确更新。但通常除非您正在使用Move自己移位比特,或进行类似的低级操作,否则不需要担心这个细节。

2
关键点在于记录是值类型,而类的实例是引用类型。一个人真正需要理解这个区别。 - David Heffernan
你也可以传递指向记录类型的指针...并获得所有引用类型的好处。如果你的记录在内存中维护(在全局未修改列表或内存映射文件中),这是一种非常方便的方式。但这可能有点技术性,不是 Delphi 的“标准”用法。用户应该更好地使用类,并仅在确实有区别时使用记录。 - Arnaud Bouchez
1
@David:是的,但是当列表本身被释放时,这些项会自动删除吗?还是在释放列表之前我需要先这么做? - Larry Lustig
2
@Larry 他们将被列表释放。实际上,只需假装你正在使用 Integer 而不是 TMyRecordType。生命周期语义是相同的。 - David Heffernan
2
啊哈!我一直没明白的概念就是TList<>与TList的内存管理行为不同。感谢您澄清了这一点。 - Larry Lustig
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接